/Collections/Specialized/ObservableDictionary.cs |
@@ -21,7 +21,7 @@ |
/// <typeparam name="V">the value type</typeparam> |
public class ObservableDictionary<K, V> : IDictionary<K, V>, INotifyCollectionChanged |
{ |
private readonly ReaderWriterLockSlim SyncRoot = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
private readonly Dictionary<K, V> store = new Dictionary<K, V>(); |
|
public bool IsVirgin { get; private set; } = true; |
@@ -30,17 +30,28 @@ |
{ |
get |
{ |
SyncRoot.EnterReadLock(); |
var v = store[key]; |
SyncRoot.ExitReadLock(); |
return v; |
_lock.EnterReadLock(); |
try |
{ |
return store[key]; |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
set |
{ |
SyncRoot.EnterWriteLock(); |
store[key] = value; |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store[key] = value; |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
} |
|
@@ -52,10 +63,15 @@ |
{ |
get |
{ |
SyncRoot.EnterReadLock(); |
var v = store.Keys; |
SyncRoot.ExitReadLock(); |
return v; |
_lock.EnterReadLock(); |
try |
{ |
return store.Keys; |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
} |
|
@@ -63,18 +79,29 @@ |
{ |
get |
{ |
SyncRoot.EnterReadLock(); |
var v = store.Values; |
SyncRoot.ExitReadLock(); |
return v; |
_lock.EnterReadLock(); |
try |
{ |
return store.Values; |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
} |
|
public void Add(KeyValuePair<K, V> item) |
{ |
SyncRoot.EnterWriteLock(); |
((IDictionary<K, V>)store).Add(item); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
((IDictionary<K, V>) store).Add(item); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); |
} |
@@ -81,9 +108,15 @@ |
|
public void Add(K key, V value) |
{ |
SyncRoot.EnterWriteLock(); |
store.Add(key, value); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.Add(key, value); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, |
new KeyValuePair<K, V>(key, value))); |
@@ -91,9 +124,15 @@ |
|
public void Clear() |
{ |
SyncRoot.EnterWriteLock(); |
store.Clear(); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.Clear(); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
if (!IsVirgin) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
IsVirgin = false; |
@@ -101,40 +140,72 @@ |
|
public bool Contains(KeyValuePair<K, V> item) |
{ |
SyncRoot.EnterReadLock(); |
var c = ((IDictionary<K, V>)store).Contains(item); |
SyncRoot.ExitReadLock(); |
return c; |
_lock.EnterReadLock(); |
try |
{ |
return ((IDictionary<K, V>) store).Contains(item); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public bool ContainsKey(K key) |
{ |
SyncRoot.EnterReadLock(); |
var c = store.ContainsKey(key); |
SyncRoot.ExitReadLock(); |
return c; |
_lock.EnterReadLock(); |
try |
{ |
return store.ContainsKey(key); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) |
{ |
SyncRoot.EnterReadLock(); |
((IDictionary<K, V>)store).CopyTo(array, arrayIndex); |
SyncRoot.ExitReadLock(); |
_lock.EnterReadLock(); |
try |
{ |
((IDictionary<K, V>) store).CopyTo(array, arrayIndex); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public IEnumerator<KeyValuePair<K, V>> GetEnumerator() |
{ |
SyncRoot.EnterReadLock(); |
var enumerator = ((IDictionary<K, V>)store).GetEnumerator(); |
SyncRoot.ExitReadLock(); |
return enumerator; |
_lock.EnterReadLock(); |
try |
{ |
using (var enumerator = ((IDictionary<K, V>)store).GetEnumerator()) |
{ |
while (enumerator.MoveNext()) |
yield return enumerator.Current; |
} |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public bool Remove(KeyValuePair<K, V> item) |
{ |
SyncRoot.EnterWriteLock(); |
var removed = ((IDictionary<K, V>)store).Remove(item); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
bool removed; |
try |
{ |
removed = ((IDictionary<K, V>) store).Remove(item); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
if (removed) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
@@ -144,12 +215,19 @@ |
public bool Remove(K key) |
{ |
KeyValuePair<K, V> item; |
SyncRoot.EnterWriteLock(); |
if (store.ContainsKey(key)) |
item = new KeyValuePair<K, V>(key, store[key]); |
_lock.EnterWriteLock(); |
bool removed; |
try |
{ |
if (store.ContainsKey(key)) |
item = new KeyValuePair<K, V>(key, store[key]); |
|
var removed = store.Remove(key); |
SyncRoot.ExitWriteLock(); |
removed = store.Remove(key); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
if (removed) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
@@ -158,18 +236,32 @@ |
|
public bool TryGetValue(K key, out V value) |
{ |
SyncRoot.EnterReadLock(); |
var c = store.TryGetValue(key, out value); |
SyncRoot.ExitReadLock(); |
return c; |
_lock.EnterReadLock(); |
try |
{ |
return store.TryGetValue(key, out value); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
IEnumerator IEnumerable.GetEnumerator() |
{ |
SyncRoot.EnterReadLock(); |
var enumerator = ((IDictionary<K, V>)store).GetEnumerator(); |
SyncRoot.ExitReadLock(); |
return enumerator; |
_lock.EnterReadLock(); |
try |
{ |
using (var enumerator = ((IDictionary<K, V>)store).GetEnumerator()) |
{ |
while (enumerator.MoveNext()) |
yield return enumerator.Current; |
} |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public event NotifyCollectionChangedEventHandler CollectionChanged; |