我正在组合一个自定义SynchronizedCollection<T>
类,以便我可以为我的 WPF 应用程序拥有一个同步的 Observable 集合。同步是通过 ReaderWriterLockSlim 提供的,在大多数情况下,它很容易应用。我遇到麻烦的情况是如何提供集合的线程安全枚举。我创建了一个自定义IEnumerator<T>
嵌套类,如下所示:
private class SynchronizedEnumerator : IEnumerator<T>
{
private SynchronizedCollection<T> _collection;
private int _currentIndex;
internal SynchronizedEnumerator(SynchronizedCollection<T> collection)
{
_collection = collection;
_collection._lock.EnterReadLock();
_currentIndex = -1;
}
#region IEnumerator<T> Members
public T Current { get; private set;}
#endregion
#region IDisposable Members
public void Dispose()
{
var collection = _collection;
if (collection != null)
collection._lock.ExitReadLock();
_collection = null;
}
#endregion
#region IEnumerator Members
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
var collection = _collection;
if (collection == null)
throw new ObjectDisposedException("SynchronizedEnumerator");
_currentIndex++;
if (_currentIndex >= collection.Count)
{
Current = default(T);
return false;
}
Current = collection[_currentIndex];
return true;
}
public void Reset()
{
if (_collection == null)
throw new ObjectDisposedException("SynchronizedEnumerator");
_currentIndex = -1;
Current = default(T);
}
#endregion
}
然而,我担心的是,如果 Enumerator 没有被 Disposed,锁将永远不会被释放。在大多数用例中,这不是问题,因为 foreach 应该正确调用 Dispose。但是,如果消费者检索显式 Enumerator 实例,则可能会出现问题。如果明确使用枚举器,我唯一的选择是使用警告实现者来记录类,提醒消费者调用 Dispose,还是有办法在最终确定期间安全地释放锁?我不这么认为,因为终结器甚至不在同一个线程上运行,但我很好奇是否还有其他方法可以改进这一点。
编辑
在考虑了这一点并阅读了回复(特别感谢 Hans)之后,我认为这绝对是一个坏主意。最大的问题其实不是忘记 Dispose,而是一个悠闲的消费者在枚举的时候制造了死锁。我现在只读取足够长的时间来获取副本并返回副本的枚举器。