这是我的帖子 Is this a correct implementation of a concurrent observable collection? 的后续.
在那篇文章中,我有一个实现通用并发可观察列表的自定义类,包括 IEnumerable<T>.GetEnumerator()
的实现。 .这是原始代码:
public IEnumerator<T> GetEnumerator()
{
var localSnapshot = _snapshot; //create local variable to protect enumerator, if class member (_snapshot) should be changed/replaced while iterating
return ((IEnumerable<T>)localSnapshot).GetEnumerator();
}
与 _snapshot
作为私有(private) Array
使用 lock()
重建的字段每当实际的内部集合 ( List<T> _list
) 被修改时。
但现在我认为 localSnapshot
根本不需要变量,代码应该是:
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_snapshot).GetEnumerator();
}
因为 localSnapshot
只是简单地分配了对与 _snapshot
相同地址的引用引用。 GetEnumerator
不关心(也不能告诉)使用了哪个变量(并且会为自己使用,当然会创建另一个引用同一数组的变量)。
如果我上面的假设是正确的,我想知道,编译器是否会优化这个变量?那么生成的代码将是相同的。或者,如果不是:理论上复制引用甚至可能是“有害的”,因为副本将比它可能更新的要少(另一个线程可以在复制完成后但在 _snapshot
之前刷新 GetEnumerator
叫做)?而且,这种“副作用”是否是编译器不优化代码的原因 - 因为优化是“无副作用”的?
最佳答案
两个版本的代码在编译后会产生相同的结果。正如 TheGeneral 在评论中指出的那样,确保的一个好方法是检查 sharplab.io .
请注意,只有在 Release 模式下编译时才会出现这种情况。如果您在 Debug 模式下编译,那么编译器会假设您可能需要中间变量来进行调试,并且不会对其进行优化。
could copying the reference theoretically even be "harmful", because the copy will be less up-to-date than it could be (another thread could refresh _snapshot after the copy was made, but before GetEnumerator is called)
如果您在 var localSnapshot = _snapshot;
之间执行一些代码,就会出现这种情况。和 return ((IEnumerable<T>)localSnapshot).GetEnumerator()
.在那种情况下,优化是不可能的。否则,在这两种情况下,您都在读取值并直接使用它。两个版本的代码在“新鲜度”上没有区别。
关于c# - C# 编译器会优化变量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53992541/