lock yield return

This commit is contained in:
neuecc 2021-09-08 19:44:27 +09:00
parent 5eff62bb5a
commit 70b0b4a5b4
32 changed files with 403 additions and 303 deletions

View File

@ -67,13 +67,28 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in list)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter); 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() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -88,7 +88,16 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -13,7 +13,7 @@ namespace ObservableCollections.Internal
readonly Func<T, TView> transform; readonly Func<T, TView> transform;
readonly Func<T, TKey> identitySelector; readonly Func<T, TKey> identitySelector;
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove. 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; ISynchronizedViewFilter<T, TView> filter;
@ -39,7 +39,7 @@ namespace ObservableCollections.Internal
dict.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
} }
this.list = dict; this.dict = dict;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
@ -50,7 +50,7 @@ namespace ObservableCollections.Internal
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
return list.Count; return dict.Count;
} }
} }
} }
@ -60,7 +60,7 @@ namespace ObservableCollections.Internal
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in dict)
{ {
filter.InvokeOnAttach(value, view); filter.InvokeOnAttach(value, view);
} }
@ -74,7 +74,7 @@ namespace ObservableCollections.Internal
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in dict)
{ {
resetAction(value, view); resetAction(value, view);
} }
@ -92,7 +92,17 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@ -116,7 +126,7 @@ namespace ObservableCollections.Internal
var value = e.NewItem; var value = e.NewItem;
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
} }
@ -126,7 +136,7 @@ namespace ObservableCollections.Internal
{ {
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
} }
@ -141,7 +151,7 @@ namespace ObservableCollections.Internal
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) if (viewMap.Remove(id, out var view))
{ {
list.Remove((view, id), out var v); dict.Remove((view, id), out var v);
filter.InvokeOnRemove(v); filter.InvokeOnRemove(v);
} }
} }
@ -152,7 +162,7 @@ namespace ObservableCollections.Internal
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) if (viewMap.Remove(id, out var view))
{ {
list.Remove((view, id), out var v); dict.Remove((view, id), out var v);
filter.InvokeOnRemove(v); filter.InvokeOnRemove(v);
} }
} }
@ -166,14 +176,14 @@ namespace ObservableCollections.Internal
var oldKey = identitySelector(oldValue); var oldKey = identitySelector(oldValue);
if (viewMap.Remove(oldKey, out var oldView)) if (viewMap.Remove(oldKey, out var oldView))
{ {
list.Remove((oldView, oldKey)); dict.Remove((oldView, oldKey));
filter.InvokeOnRemove(oldValue, oldView); filter.InvokeOnRemove(oldValue, oldView);
} }
var value = e.NewItem; var value = e.NewItem;
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
@ -193,12 +203,12 @@ namespace ObservableCollections.Internal
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter()) if (!filter.IsNullFilter())
{ {
foreach (var item in list) foreach (var item in dict)
{ {
filter.InvokeOnRemove(item.Value); filter.InvokeOnRemove(item.Value);
} }
} }
list.Clear(); dict.Clear();
viewMap.Clear(); viewMap.Clear();
break; break;
default: default:

View File

@ -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);
}
}
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 08405416bc7c7e04e9bcaa4fa13c875f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 98be7e821cfba26469f0911671fb24b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -103,9 +103,17 @@ namespace ObservableCollections
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator() public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
{ {
return new SynchronizedViewEnumerator<KeyValuePair<TKey, TValue>, TView>(SyncRoot, lock (SyncRoot)
dict.Select(x => (new KeyValuePair<TKey, TValue>(x.Key, x.Value.Item1), x.Value.Item2)).GetEnumerator(), {
filter); 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() IEnumerator IEnumerable.GetEnumerator()

View File

@ -211,7 +211,13 @@ namespace ObservableCollections
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 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() IEnumerator IEnumerable.GetEnumerator()

View File

@ -280,7 +280,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in buffer)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -88,7 +88,16 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -247,7 +247,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, set.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in set)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in list)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -139,7 +139,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, list.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in list)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in queue)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -203,7 +203,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, queue.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in queue)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -91,13 +91,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in ringBuffer)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -195,7 +195,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in buffer)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in stack)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -199,7 +199,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in stack)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -67,13 +67,28 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in list)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter); 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() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -88,7 +88,16 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -13,7 +13,7 @@ namespace ObservableCollections.Internal
readonly Func<T, TView> transform; readonly Func<T, TView> transform;
readonly Func<T, TKey> identitySelector; readonly Func<T, TKey> identitySelector;
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove. 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; ISynchronizedViewFilter<T, TView> filter;
@ -39,7 +39,7 @@ namespace ObservableCollections.Internal
dict.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
} }
this.list = dict; this.dict = dict;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
@ -50,7 +50,7 @@ namespace ObservableCollections.Internal
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
return list.Count; return dict.Count;
} }
} }
} }
@ -60,7 +60,7 @@ namespace ObservableCollections.Internal
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in dict)
{ {
filter.InvokeOnAttach(value, view); filter.InvokeOnAttach(value, view);
} }
@ -74,7 +74,7 @@ namespace ObservableCollections.Internal
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in dict)
{ {
resetAction(value, view); resetAction(value, view);
} }
@ -92,7 +92,17 @@ namespace ObservableCollections.Internal
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@ -116,7 +126,7 @@ namespace ObservableCollections.Internal
var value = e.NewItem; var value = e.NewItem;
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
} }
@ -126,7 +136,7 @@ namespace ObservableCollections.Internal
{ {
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
} }
@ -141,7 +151,7 @@ namespace ObservableCollections.Internal
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) if (viewMap.Remove(id, out var view))
{ {
list.Remove((view, id), out var v); dict.Remove((view, id), out var v);
filter.InvokeOnRemove(v); filter.InvokeOnRemove(v);
} }
} }
@ -152,7 +162,7 @@ namespace ObservableCollections.Internal
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) if (viewMap.Remove(id, out var view))
{ {
list.Remove((view, id), out var v); dict.Remove((view, id), out var v);
filter.InvokeOnRemove(v); filter.InvokeOnRemove(v);
} }
} }
@ -166,14 +176,14 @@ namespace ObservableCollections.Internal
var oldKey = identitySelector(oldValue); var oldKey = identitySelector(oldValue);
if (viewMap.Remove(oldKey, out var oldView)) if (viewMap.Remove(oldKey, out var oldView))
{ {
list.Remove((oldView, oldKey)); dict.Remove((oldView, oldKey));
filter.InvokeOnRemove(oldValue, oldView); filter.InvokeOnRemove(oldValue, oldView);
} }
var value = e.NewItem; var value = e.NewItem;
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); dict.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.InvokeOnAdd(value, view); filter.InvokeOnAdd(value, view);
@ -193,12 +203,12 @@ namespace ObservableCollections.Internal
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter()) if (!filter.IsNullFilter())
{ {
foreach (var item in list) foreach (var item in dict)
{ {
filter.InvokeOnRemove(item.Value); filter.InvokeOnRemove(item.Value);
} }
} }
list.Clear(); dict.Clear();
viewMap.Clear(); viewMap.Clear();
break; break;
default: default:

View File

@ -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);
}
}
}
}
}
}

View File

@ -103,9 +103,17 @@ namespace ObservableCollections
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator() public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
{ {
return new SynchronizedViewEnumerator<KeyValuePair<TKey, TValue>, TView>(SyncRoot, lock (SyncRoot)
dict.Select(x => (new KeyValuePair<TKey, TValue>(x.Key, x.Value.Item1), x.Value.Item2)).GetEnumerator(), {
filter); 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() IEnumerator IEnumerable.GetEnumerator()

View File

@ -88,7 +88,16 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@ -247,7 +247,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, set.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in set)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in list)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in queue)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, queue.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -91,13 +91,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in ringBuffer)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, ringBuffer.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -90,13 +90,28 @@ namespace ObservableCollections
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<(T, TView)> GetEnumerator()
{ {
if (!reverse) lock (SyncRoot)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.GetEnumerator(), filter); if (!reverse)
} {
else foreach (var item in stack)
{ {
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, stack.AsEnumerable().Reverse().GetEnumerator(), filter); 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;
}
}
}
} }
} }

View File

@ -199,7 +199,13 @@ namespace ObservableCollections
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator()); lock (SyncRoot)
{
foreach (var item in stack)
{
yield return item;
}
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()