lock yield return
This commit is contained in:
parent
5eff62bb5a
commit
70b0b4a5b4
@ -67,13 +67,28 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in list.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +162,16 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, array.AsEnumerable().GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in array)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -88,7 +88,16 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, dict.Select(x => x.Value).GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -13,7 +13,7 @@ namespace ObservableCollections.Internal
|
||||
readonly Func<T, TView> transform;
|
||||
readonly Func<T, TKey> identitySelector;
|
||||
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove.
|
||||
readonly SortedDictionary<(TView View, TKey Key), (T Value, TView View)> list;
|
||||
readonly SortedDictionary<(TView View, TKey Key), (T Value, TView View)> dict;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
@ -39,7 +39,7 @@ namespace ObservableCollections.Internal
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
}
|
||||
this.list = dict;
|
||||
this.dict = dict;
|
||||
this.source.CollectionChanged += SourceCollectionChanged;
|
||||
}
|
||||
}
|
||||
@ -50,7 +50,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return list.Count;
|
||||
return dict.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,7 +60,7 @@ namespace ObservableCollections.Internal
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (_, (value, view)) in list)
|
||||
foreach (var (_, (value, view)) in dict)
|
||||
{
|
||||
filter.InvokeOnAttach(value, view);
|
||||
}
|
||||
@ -74,7 +74,7 @@ namespace ObservableCollections.Internal
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (_, (value, view)) in list)
|
||||
foreach (var (_, (value, view)) in dict)
|
||||
{
|
||||
resetAction(value, view);
|
||||
}
|
||||
@ -92,7 +92,17 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.Select(x => x.Value).GetEnumerator(), filter);
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
@ -116,7 +126,7 @@ namespace ObservableCollections.Internal
|
||||
var value = e.NewItem;
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
@ -126,7 +136,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
@ -141,7 +151,7 @@ namespace ObservableCollections.Internal
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id), out var v);
|
||||
dict.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
@ -152,7 +162,7 @@ namespace ObservableCollections.Internal
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id), out var v);
|
||||
dict.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
@ -166,14 +176,14 @@ namespace ObservableCollections.Internal
|
||||
var oldKey = identitySelector(oldValue);
|
||||
if (viewMap.Remove(oldKey, out var oldView))
|
||||
{
|
||||
list.Remove((oldView, oldKey));
|
||||
dict.Remove((oldView, oldKey));
|
||||
filter.InvokeOnRemove(oldValue, oldView);
|
||||
}
|
||||
|
||||
var value = e.NewItem;
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
|
||||
filter.InvokeOnAdd(value, view);
|
||||
@ -193,12 +203,12 @@ namespace ObservableCollections.Internal
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in list)
|
||||
foreach (var item in dict)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Value);
|
||||
}
|
||||
}
|
||||
list.Clear();
|
||||
dict.Clear();
|
||||
viewMap.Clear();
|
||||
break;
|
||||
default:
|
||||
|
@ -1,46 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ObservableCollections.Internal
|
||||
{
|
||||
internal class SynchronizedEnumerator<T> : IEnumerator<T>
|
||||
{
|
||||
bool isDisposed;
|
||||
readonly object gate;
|
||||
readonly bool lockTaken;
|
||||
readonly IEnumerator<T> enumerator;
|
||||
|
||||
public SynchronizedEnumerator(object gate, IEnumerator<T> enumerator)
|
||||
{
|
||||
this.gate = gate;
|
||||
this.enumerator = enumerator;
|
||||
Monitor.Enter(gate, ref lockTaken);
|
||||
}
|
||||
|
||||
public T Current => enumerator.Current;
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
public bool MoveNext() => enumerator.MoveNext();
|
||||
public void Reset() => enumerator.Reset();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
try
|
||||
{
|
||||
enumerator.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
{
|
||||
Monitor.Exit(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08405416bc7c7e04e9bcaa4fa13c875f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ObservableCollections.Internal
|
||||
{
|
||||
internal class SynchronizedViewEnumerator<T, TView> : IEnumerator<(T, TView)>, IDisposable
|
||||
{
|
||||
bool isDisposed;
|
||||
readonly bool lockTaken;
|
||||
readonly object gate;
|
||||
readonly IEnumerator<(T, TView)> enumerator;
|
||||
readonly ISynchronizedViewFilter<T, TView> filter;
|
||||
(T, TView) current;
|
||||
|
||||
public SynchronizedViewEnumerator(object gate, IEnumerator<(T, TView)> enumerator, ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
this.gate = gate;
|
||||
this.enumerator = enumerator;
|
||||
this.filter = filter;
|
||||
this.current = default;
|
||||
this.isDisposed = false;
|
||||
Monitor.Enter(gate, ref lockTaken);
|
||||
}
|
||||
|
||||
public (T, TView) Current => current;
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
current = enumerator.Current;
|
||||
if (filter.IsMatch(current.Item1, current.Item2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void Reset() => throw new NotSupportedException();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
try
|
||||
{
|
||||
enumerator.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
{
|
||||
Monitor.Exit(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98be7e821cfba26469f0911671fb24b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -103,9 +103,17 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<KeyValuePair<TKey, TValue>, TView>(SyncRoot,
|
||||
dict.Select(x => (new KeyValuePair<TKey, TValue>(x.Key, x.Value.Item1), x.Value.Item2)).GetEnumerator(),
|
||||
filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
|
||||
if (filter.IsMatch(v.Item1, v.Item2))
|
||||
{
|
||||
yield return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -211,7 +211,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<KeyValuePair<TKey, TValue>>(SyncRoot, dictionary.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dictionary)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -280,7 +280,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in buffer)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -88,7 +88,16 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, dict.Select(x => x.Value).GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Item1, item.Value.Item2))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -247,7 +247,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, set.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in set)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in list.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, list.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in queue)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in queue.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, queue.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in queue)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -91,13 +91,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in ringBuffer)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in ringBuffer.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in buffer)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in stack)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in stack.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in stack)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -67,13 +67,28 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in list.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +162,16 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, array.AsEnumerable().GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in array)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -88,7 +88,16 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, dict.Select(x => x.Value).GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -13,7 +13,7 @@ namespace ObservableCollections.Internal
|
||||
readonly Func<T, TView> transform;
|
||||
readonly Func<T, TKey> identitySelector;
|
||||
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove.
|
||||
readonly SortedDictionary<(TView View, TKey Key), (T Value, TView View)> list;
|
||||
readonly SortedDictionary<(TView View, TKey Key), (T Value, TView View)> dict;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
@ -39,7 +39,7 @@ namespace ObservableCollections.Internal
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
}
|
||||
this.list = dict;
|
||||
this.dict = dict;
|
||||
this.source.CollectionChanged += SourceCollectionChanged;
|
||||
}
|
||||
}
|
||||
@ -50,7 +50,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return list.Count;
|
||||
return dict.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,7 +60,7 @@ namespace ObservableCollections.Internal
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (_, (value, view)) in list)
|
||||
foreach (var (_, (value, view)) in dict)
|
||||
{
|
||||
filter.InvokeOnAttach(value, view);
|
||||
}
|
||||
@ -74,7 +74,7 @@ namespace ObservableCollections.Internal
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (_, (value, view)) in list)
|
||||
foreach (var (_, (value, view)) in dict)
|
||||
{
|
||||
resetAction(value, view);
|
||||
}
|
||||
@ -92,7 +92,17 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.Select(x => x.Value).GetEnumerator(), filter);
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
@ -116,7 +126,7 @@ namespace ObservableCollections.Internal
|
||||
var value = e.NewItem;
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
@ -126,7 +136,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
@ -141,7 +151,7 @@ namespace ObservableCollections.Internal
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id), out var v);
|
||||
dict.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
@ -152,7 +162,7 @@ namespace ObservableCollections.Internal
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id), out var v);
|
||||
dict.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
@ -166,14 +176,14 @@ namespace ObservableCollections.Internal
|
||||
var oldKey = identitySelector(oldValue);
|
||||
if (viewMap.Remove(oldKey, out var oldView))
|
||||
{
|
||||
list.Remove((oldView, oldKey));
|
||||
dict.Remove((oldView, oldKey));
|
||||
filter.InvokeOnRemove(oldValue, oldView);
|
||||
}
|
||||
|
||||
var value = e.NewItem;
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
dict.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
|
||||
filter.InvokeOnAdd(value, view);
|
||||
@ -193,12 +203,12 @@ namespace ObservableCollections.Internal
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in list)
|
||||
foreach (var item in dict)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Value);
|
||||
}
|
||||
}
|
||||
list.Clear();
|
||||
dict.Clear();
|
||||
viewMap.Clear();
|
||||
break;
|
||||
default:
|
||||
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ObservableCollections.Internal
|
||||
{
|
||||
internal class SynchronizedViewEnumerator<T, TView> : IEnumerator<(T, TView)>, IDisposable
|
||||
{
|
||||
bool isDisposed;
|
||||
readonly bool lockTaken;
|
||||
readonly object gate;
|
||||
readonly IEnumerator<(T, TView)> enumerator;
|
||||
readonly ISynchronizedViewFilter<T, TView> filter;
|
||||
(T, TView) current;
|
||||
|
||||
public SynchronizedViewEnumerator(object gate, IEnumerator<(T, TView)> enumerator, ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
this.gate = gate;
|
||||
this.enumerator = enumerator;
|
||||
this.filter = filter;
|
||||
this.current = default;
|
||||
this.isDisposed = false;
|
||||
Monitor.Enter(gate, ref lockTaken);
|
||||
}
|
||||
|
||||
public (T, TView) Current => current;
|
||||
object IEnumerator.Current => Current!;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
current = enumerator.Current;
|
||||
if (filter.IsMatch(current.Item1, current.Item2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void Reset() => throw new NotSupportedException();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
try
|
||||
{
|
||||
enumerator.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
{
|
||||
Monitor.Exit(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -103,9 +103,17 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<KeyValuePair<TKey, TValue>, TView>(SyncRoot,
|
||||
dict.Select(x => (new KeyValuePair<TKey, TValue>(x.Key, x.Value.Item1), x.Value.Item2)).GetEnumerator(),
|
||||
filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
|
||||
if (filter.IsMatch(v.Item1, v.Item2))
|
||||
{
|
||||
yield return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -88,7 +88,16 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, dict.Select(x => x.Value).GetEnumerator(), filter);
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
if (filter.IsMatch(item.Value.Item1, item.Value.Item2))
|
||||
{
|
||||
yield return item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
@ -247,7 +247,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, set.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in set)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in list.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in queue)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in queue.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,13 +91,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in ringBuffer)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in ringBuffer.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,13 +90,28 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
if (!reverse)
|
||||
{
|
||||
foreach (var item in stack)
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in stack.AsEnumerable().Reverse())
|
||||
{
|
||||
if (filter.IsMatch(item.Item1, item.Item2))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,13 @@ namespace ObservableCollections
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator());
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var item in stack)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
Loading…
x
Reference in New Issue
Block a user