我正在整理一个自定义的SynchronizedCollection T class,以便我可以为我的 WPF应用程序提供一个同步的Observable集合.同步是通过ReaderWriterLockSlim提供的,在大多数情况下,它很容易应用.我遇到问题
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实例,则可能会出现问题.我唯一的选择是使用一个警告实现者来记录该类,提醒消费者在明确使用Enumerator时调用Dispose,或者有没有办法在最终确定期间安全地释放锁定?我想不是,因为终结器甚至没有在同一个线程上运行,但我很好奇是否还有其他方法来改进它.
编辑
在考虑了这一点并阅读了回复之后(特别感谢Hans),我认为这绝对是一个坏主意.实际上,最大的问题不是忘记Dispose,而是一个悠闲的消费者在枚举时创造僵局.我现在只读取锁定足够长的时间来获取副本并返回副本的枚举器.
你是对的,这是一个问题.终结器是没用的,它运行得太晚,无法使用.无论如何,代码应该在此之前严重陷入僵局.不幸的是,您无法区分调用MoveNext / Current成员的foreach或显式使用它们的客户端代码.没有修复,不要这样做.微软也没有这样做,他们有充分的理由支持.NET 1.x.您可以创建的唯一真正的线程安全迭代器是在GetEnumerator()方法中创建集合对象的副本的迭代器.迭代器与集合不同步也不是快乐.
