/Collections/Specialized/ObservableHashSet.cs |
@@ -22,14 +22,20 @@ |
/// <typeparam name="T">the object type</typeparam> |
public class ObservableHashSet<T> : ICollection<T>, INotifyCollectionChanged, IEnumerable<T> |
{ |
private readonly ReaderWriterLockSlim SyncRoot = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
private readonly HashSet<T> store = new HashSet<T>(); |
|
public ObservableHashSet(HashSet<T> set) |
{ |
SyncRoot.EnterWriteLock(); |
UnionWith(set); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
UnionWith(set); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
|
public ObservableHashSet() |
@@ -38,23 +44,41 @@ |
|
public ObservableHashSet(T item) |
{ |
SyncRoot.EnterWriteLock(); |
Add(item); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
Add(item); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
|
public ObservableHashSet(ObservableHashSet<T> other) |
{ |
SyncRoot.EnterWriteLock(); |
UnionWith(other); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
UnionWith(other); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
|
public ObservableHashSet(IEnumerable<T> list) |
{ |
SyncRoot.EnterWriteLock(); |
UnionWith(list); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
UnionWith(list); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
|
public bool IsVirgin { get; private set; } = true; |
@@ -61,25 +85,49 @@ |
|
public IEnumerator<T> GetEnumerator() |
{ |
SyncRoot.EnterReadLock(); |
var enumerator = store.GetEnumerator(); |
SyncRoot.ExitReadLock(); |
return enumerator; |
_lock.EnterReadLock(); |
try |
{ |
using (var enumerator = store.GetEnumerator()) |
{ |
while (enumerator.MoveNext()) |
yield return enumerator.Current; |
} |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
IEnumerator IEnumerable.GetEnumerator() |
{ |
SyncRoot.EnterReadLock(); |
var enumerator = GetEnumerator(); |
SyncRoot.ExitReadLock(); |
return enumerator; |
_lock.EnterReadLock(); |
try |
{ |
using (var enumerator = store.GetEnumerator()) |
{ |
while (enumerator.MoveNext()) |
yield return enumerator.Current; |
} |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public void Add(T item) |
{ |
SyncRoot.EnterWriteLock(); |
store.Add(item); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.Add(item); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); |
} |
@@ -86,9 +134,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; |
@@ -96,24 +150,42 @@ |
|
public bool Contains(T item) |
{ |
SyncRoot.EnterReadLock(); |
var contains = store.Contains(item); |
SyncRoot.ExitReadLock(); |
return contains; |
_lock.EnterReadLock(); |
try |
{ |
return store.Contains(item); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public void CopyTo(T[] array, int arrayIndex) |
{ |
SyncRoot.EnterReadLock(); |
store.CopyTo(array, arrayIndex); |
SyncRoot.ExitReadLock(); |
_lock.EnterReadLock(); |
try |
{ |
store.CopyTo(array, arrayIndex); |
} |
finally |
{ |
if (_lock.IsReadLockHeld) _lock.ExitReadLock(); |
} |
} |
|
public bool Remove(T item) |
{ |
SyncRoot.EnterWriteLock(); |
var removed = store.Remove(item); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
bool removed; |
try |
{ |
removed = store.Remove(item); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
IsVirgin = false; |
if (removed) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
@@ -129,9 +201,15 @@ |
public void UnionWith(IEnumerable<T> list) |
{ |
var added = new List<T>(list.Except(store)); |
SyncRoot.EnterWriteLock(); |
store.UnionWith(added); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.UnionWith(added); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
if (!IsVirgin && added.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added)); |
IsVirgin = false; |
@@ -145,9 +223,15 @@ |
public void ExceptWith(IEnumerable<T> list) |
{ |
var removed = new List<T>(list.Intersect(store)); |
SyncRoot.EnterWriteLock(); |
store.ExceptWith(removed); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.ExceptWith(removed); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
if (!IsVirgin && removed.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
removed)); |
@@ -157,9 +241,15 @@ |
public void RemoveWhere(Func<T, bool> func) |
{ |
var removed = new List<T>(store.Where(func)); |
SyncRoot.EnterWriteLock(); |
store.ExceptWith(removed); |
SyncRoot.ExitWriteLock(); |
_lock.EnterWriteLock(); |
try |
{ |
store.ExceptWith(removed); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
if (!IsVirgin && removed.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
removed)); |
@@ -168,10 +258,15 @@ |
|
public IEnumerable<T> AsEnumerable() |
{ |
SyncRoot.EnterWriteLock(); |
var enumerable = store.AsEnumerable(); |
SyncRoot.ExitWriteLock(); |
return enumerable; |
_lock.EnterWriteLock(); |
try |
{ |
return store.AsEnumerable(); |
} |
finally |
{ |
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); |
} |
} |
} |
} |