这是我的帖子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
是一个专用的Array
字段,只要修改了内部内部集合(lock()
),就会使用List<T> _list
对其进行重建。
但是现在我认为根本不需要localSnapshot
变量,代码应该是:
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_snapshot).GetEnumerator();
}
因为localSnapshot
仅被分配了对_snapshot
所引用的同一地址的引用。 GetEnumerator
不在乎(也无法说出)使用了哪个变量(当然,它会为自己使用而创建另一个引用同一数组的变量)。
如果以上假设是正确的,我想知道编译器是否会将变量优化掉?那么结果代码将是相同的。或者,如果不是,则:从理论上讲,复制引用甚至可能是“有害的”,因为该副本将比其最新版本少(另一个线程可以在复制后但在{之前刷新_snapshot
{1}}被称为)?并且,这种“副作用”是编译器不优化代码的原因-因为优化是“无副作用的”吗?
答案 0 :(得分:1)
两个版本的代码在编译后将产生相同的结果。正如TheGeneral在评论中指出的那样,一种确定的好方法是检查sharplab.io。
请注意,仅当您在发布模式下编译时,这才是正确的。如果您在Debug模式下进行编译,则编译器会假定您可能需要中介变量来进行调试,并且不会对其进行优化。
从理论上讲,甚至可以复制引用是“有害的”,因为该副本将不如其最新(复制后,但在调用GetEnumerator之前,另一个线程可以刷新_snapshot)
如果您在var localSnapshot = _snapshot;
和return ((IEnumerable<T>)localSnapshot).GetEnumerator()
之间执行了一些代码,情况就是这样。在那种情况下,优化是不可能的。否则,在两种情况下,您都将读取值并直接使用它。两个版本的代码之间的“新鲜度”没有区别。