我创建了一个使用SortedDictionary
来存储和操作数据的类。除非在多线程环境中实现,否则该类很有效。现在,我想通过为内部SortedDictionary
类编写包装类来使类线程安全。我想使用Reader-Writer Locks来实现它,但是现在,我在编写包装器本身时遇到了问题。具体来说,我不确定如何为字典实现Enumerator
。这是我现在的完整代码。
public class ConcurrentSortedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
#region Variables
SortedDictionary<TKey, TValue> _dict;
#endregion
#region Constructors
public ConcurrentSortedDictionary()
{
_dict = new SortedDictionary<TKey, TValue>();
}
public ConcurrentSortedDictionary(IComparer<TKey> comparer)
{
_dict = new SortedDictionary<TKey, TValue>(comparer);
}
public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary)
{
_dict = new SortedDictionary<TKey, TValue>(dictionary);
}
public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
{
_dict = new SortedDictionary<TKey, TValue>(dictionary, comparer);
}
#endregion
#region Properties
public IComparer<TKey> Comparer
{
get
{
return _dict.Comparer;
}
}
public int Count
{
get
{
return _dict.Count;
}
}
public TValue this[TKey key]
{
get
{
return _dict[key];
}
set
{
_dict[key] = value;
}
}
public SortedDictionary<TKey, TValue>.KeyCollection Keys
{
get
{
return new SortedDictionary<TKey,TValue>.KeyCollection(_dict);
}
}
public SortedDictionary<TKey, TValue>.ValueCollection Values
{
get
{
return new SortedDictionary<TKey, TValue>.ValueCollection(_dict);
}
}
#endregion
#region Methods
public void Add(TKey key, TValue value)
{
_dict.Add(key, value);
}
public void Clear()
{
_dict.Clear();
}
public bool ContainsKey(TKey key)
{
return _dict.ContainsKey(key);
}
public bool ContainsValue(TValue value)
{
return _dict.ContainsValue(value);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
{
_dict.CopyTo(array, index);
}
public override bool Equals(Object obj)
{
return _dict.Equals(obj);
}
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
public override int GetHashCode()
{
return _dict.GetHashCode();
}
public bool Remove(TKey key)
{
return _dict.Remove(key);
}
public override string ToString()
{
return _dict.ToString();
}
public bool TryGetValue(TKey key, out TValue value)
{
return _dict.TryGetValue(key, out value);
}
#endregion
}
编译代码时,收到错误消息:
'ConcurrentSortedDictionary'没有实现接口 member'System.Collections.IEnumerable.GetEnumerator()'。 'ConcurrentSortedDictionary.GetEnumerator()'不能 实现'System.Collections.IEnumerable.GetEnumerator()'因为它 没有匹配的返回类型 'System.Collections.IEnumerator'。
我在这里看了几篇与此相关的帖子作为参考:
How do I implement IEnumerable in my Dictionary wrapper class that implements IEnumerable<Foo>? What's the best way of implementing a thread-safe Dictionary?
但我不明白我做错了什么。非常感谢任何帮助。
答案 0 :(得分:2)
问题在于:
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
你需要:
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _dict.GetEnumerator();
}
第二个非泛型GetEnumerator()
是一个explicit interface implementation,需要作为C#中存在泛型和泛型集合之前的不幸回归。
另请参阅:IEnumerable<T> provides two GetEnumerator methods - what is the difference between them?(特别是Michael B's answer)。
但是如果您希望枚举与其他类一起是线程安全的,您可能还需要编写自己的线程安全IEnumerator
类型,它与读者合作/作家锁在你的班级!
答案 1 :(得分:1)
在实施dvnrrs的建议之后,我现在让班级运作良好。我甚至为IEnumerable接口添加了一个包装类来保护SortedDictionary的枚举(这里的代码修改的代码如下:http://www.codeproject.com/Articles/56575/Thread-safe-enumeration-in-C)。以下是包含Reader-Writer Locks的更新代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
public class SafeEnumerator<T> : IEnumerator<T>
{
#region Variables
// this is the (thread-unsafe)
// enumerator of the underlying collection
private readonly IEnumerator<T> _enumerator;
// this is the object we shall lock on.
private ReaderWriterLockSlim _lock;
#endregion
#region Constructor
public SafeEnumerator(IEnumerator<T> inner, ReaderWriterLockSlim readWriteLock)
{
_enumerator = inner;
_lock = readWriteLock;
// Enter lock in constructor
_lock.EnterReadLock();
}
#endregion
#region Implementation of IDisposable
public void Dispose()
{
// .. and exiting lock on Dispose()
// This will be called when the foreach loop finishes
_lock.ExitReadLock();
}
#endregion
#region Implementation of IEnumerator
// we just delegate actual implementation
// to the inner enumerator, that actually iterates
// over some collection
public bool MoveNext()
{
return _enumerator.MoveNext();
}
public void Reset()
{
_enumerator.Reset();
}
public T Current
{
get
{
return _enumerator.Current;
}
}
object IEnumerator.Current
{
get
{
return Current;
}
}
#endregion
}
public class ConcurrentSortedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
#region Variables
private ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
SortedDictionary<TKey, TValue> _dict;
#endregion
#region Constructors
public ConcurrentSortedDictionary()
{
_dict = new SortedDictionary<TKey, TValue>();
}
public ConcurrentSortedDictionary(IComparer<TKey> comparer)
{
_dict = new SortedDictionary<TKey, TValue>(comparer);
}
public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary)
{
_dict = new SortedDictionary<TKey, TValue>(dictionary);
}
public ConcurrentSortedDictionary(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
{
_dict = new SortedDictionary<TKey, TValue>(dictionary, comparer);
}
#endregion
#region Properties
public IComparer<TKey> Comparer
{
get
{
_readWriteLock.EnterReadLock();
try
{
return _dict.Comparer;
}
finally
{
_readWriteLock.ExitReadLock();
}
}
}
public int Count
{
get
{
_readWriteLock.EnterReadLock();
try
{
return _dict.Count;
}
finally
{
_readWriteLock.ExitReadLock();
}
}
}
public TValue this[TKey key]
{
get
{
_readWriteLock.EnterReadLock();
try
{
return _dict[key];
}
finally
{
_readWriteLock.ExitReadLock();
}
}
set
{
_readWriteLock.EnterWriteLock();
try
{
_dict[key] = value;
}
finally
{
_readWriteLock.ExitWriteLock();
}
}
}
public SortedDictionary<TKey, TValue>.KeyCollection Keys
{
get
{
_readWriteLock.EnterReadLock();
try
{
return new SortedDictionary<TKey, TValue>.KeyCollection(_dict);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
}
public SortedDictionary<TKey, TValue>.ValueCollection Values
{
get
{
_readWriteLock.EnterReadLock();
try
{
return new SortedDictionary<TKey, TValue>.ValueCollection(_dict);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
}
#endregion
#region Methods
public void Add(TKey key, TValue value)
{
_readWriteLock.EnterWriteLock();
try
{
_dict.Add(key, value);
}
finally
{
_readWriteLock.ExitWriteLock();
}
}
public void Clear()
{
_readWriteLock.EnterWriteLock();
try
{
_dict.Clear();
}
finally
{
_readWriteLock.ExitWriteLock();
}
}
public bool ContainsKey(TKey key)
{
_readWriteLock.EnterReadLock();
try
{
return _dict.ContainsKey(key);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public bool ContainsValue(TValue value)
{
_readWriteLock.EnterReadLock();
try
{
return _dict.ContainsValue(value);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
{
_readWriteLock.EnterReadLock();
try
{
_dict.CopyTo(array, index);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public override bool Equals(Object obj)
{
_readWriteLock.EnterReadLock();
try
{
return _dict.Equals(obj);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return new SafeEnumerator<KeyValuePair<TKey, TValue>>(_dict.GetEnumerator(), _readWriteLock);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new SafeEnumerator<KeyValuePair<TKey, TValue>>(_dict.GetEnumerator(), _readWriteLock);
}
public override int GetHashCode()
{
_readWriteLock.EnterReadLock();
try
{
return _dict.GetHashCode();
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public bool Remove(TKey key)
{
_readWriteLock.EnterWriteLock();
try
{
return _dict.Remove(key);
}
finally
{
_readWriteLock.ExitWriteLock();
}
}
public override string ToString()
{
_readWriteLock.EnterReadLock();
try
{
return _dict.ToString();
}
finally
{
_readWriteLock.ExitReadLock();
}
}
public bool TryGetValue(TKey key, out TValue value)
{
_readWriteLock.EnterReadLock();
try
{
return _dict.TryGetValue(key, out value);
}
finally
{
_readWriteLock.ExitReadLock();
}
}
#endregion
}