Safe Rope SortedDictionary

I created a class that uses a SortedDictionary to store and process data. A class works fine, except when implemented in a multi-threaded environment. Now I would like to make the class thread safe by writing a wrapper class for the inner class SortedDictionary. I would like to use Lock-Writer Locks to implement this, but at the moment I have problems writing the wrapper class itself. In particular, I'm not sure how to implement Enumerator for a dictionary. Here is my complete code for the class that is standing now.

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 } 

When I compile the code, I get an error message:

'ConcurrentSortedDictionary' does not implement the member interface of 'System.Collections.IEnumerable.GetEnumerator ()'. 'ConcurrentSortedDictionary.GetEnumerator ()' cannot implement 'System.Collections.IEnumerable.GetEnumerator ()' because it does not have the corresponding return type 'System.Collections.IEnumerator'.

I reviewed a few posts related to this as a reference:

How to implement IEnumerable in my Dictionary wrapper class that implements IEnumerable <Foo>? What is the best way to implement a thread safe dictionary?

but I do not see what I am doing wrong. Any help is much appreciated, thanks!

Jason Oh

+6
source share
2 answers

After implementing the dvnrrs clause, my class now works fine. I even added a wrapper class for the IEnumerable interface to protect SortedDictionary enumerations (the code changed in this example here: http://www.codeproject.com/Articles/56575/Thread-safe-enumeration-in-C ). Here is the updated code with Lock-Writer Lock enabled:

 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 } 
+1
source

The problem is here:

 IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() { return GetEnumerator(); } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dict.GetEnumerator(); } 

You need:

 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dict.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _dict.GetEnumerator(); } 

The second non-generic GetEnumerator() is an explicit implementation of the interface and is needed as an unsuccessful return to the days preceding the generics and generic collections that existed in C #.

See also: IEnumerable <T> provides two GetEnumerator methods - what is the difference between them? (and in particular, Answer by Michael B. ).

However , if you want the enumeration to be thread safe along with the rest of your class, you might also need to write your own thread safe type IEnumerator , which interacts with the lock reader / writer in your class!

+2
source

All Articles