diff --git a/.editorconfig b/.editorconfig index 42fdb0221..e60f5624d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -361,7 +361,7 @@ dotnet_diagnostic.SA1113.severity = error dotnet_diagnostic.SA1114.severity = none dotnet_diagnostic.SA1115.severity = error dotnet_diagnostic.SA1116.severity = none -dotnet_diagnostic.SA1117.severity = error +dotnet_diagnostic.SA1117.severity = none dotnet_diagnostic.SA1118.severity = none dotnet_diagnostic.SA1119.severity = error dotnet_diagnostic.SA1120.severity = error @@ -380,7 +380,7 @@ dotnet_diagnostic.SA1133.severity = error dotnet_diagnostic.SA1134.severity = error dotnet_diagnostic.SA1135.severity = error dotnet_diagnostic.SA1136.severity = error -dotnet_diagnostic.SA1137.severity = error +dotnet_diagnostic.SA1137.severity = none dotnet_diagnostic.SA1139.severity = error dotnet_diagnostic.SA1200.severity = none dotnet_diagnostic.SA1201.severity = none diff --git a/src/DynamicData/Aggregation/SumEx.cs b/src/DynamicData/Aggregation/SumEx.cs index 71c2fe205..71d8c4e61 100644 --- a/src/DynamicData/Aggregation/SumEx.cs +++ b/src/DynamicData/Aggregation/SumEx.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Aggregation; /// diff --git a/src/DynamicData/Alias/ObservableCacheAlias.cs b/src/DynamicData/Alias/ObservableCacheAlias.cs index 38b9c5aa3..767574761 100644 --- a/src/DynamicData/Alias/ObservableCacheAlias.cs +++ b/src/DynamicData/Alias/ObservableCacheAlias.cs @@ -4,8 +4,6 @@ using System.Reactive; -using DynamicData.Kernel; - namespace DynamicData.Alias; /// diff --git a/src/DynamicData/Binding/ExpressionBuilder.cs b/src/DynamicData/Binding/ExpressionBuilder.cs index 4642dc69e..ff0ccbfb4 100644 --- a/src/DynamicData/Binding/ExpressionBuilder.cs +++ b/src/DynamicData/Binding/ExpressionBuilder.cs @@ -5,7 +5,6 @@ using System.ComponentModel; using System.Linq.Expressions; using System.Reactive; -using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reflection; diff --git a/src/DynamicData/Binding/ObservableCollectionEx.cs b/src/DynamicData/Binding/ObservableCollectionEx.cs index 6e6c5f25f..4696f80af 100644 --- a/src/DynamicData/Binding/ObservableCollectionEx.cs +++ b/src/DynamicData/Binding/ObservableCollectionEx.cs @@ -6,7 +6,6 @@ using System.Collections.Specialized; using System.Reactive; using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Binding; diff --git a/src/DynamicData/Binding/SortAndBind.cs b/src/DynamicData/Binding/SortAndBind.cs index 22ce39ab5..01b30231f 100644 --- a/src/DynamicData/Binding/SortAndBind.cs +++ b/src/DynamicData/Binding/SortAndBind.cs @@ -65,7 +65,7 @@ public SortAndBind(IObservable> source, comparerChanged = comparerChanged.ObserveOn(scheduler); } - var locker = new object(); + var locker = InternalEx.NewLock(); SortApplicator? sortApplicator = null; // Create a new sort applicator each time. diff --git a/src/DynamicData/Cache/CacheChangeSetEx.cs b/src/DynamicData/Cache/CacheChangeSetEx.cs index 382857b45..5baca5d39 100644 --- a/src/DynamicData/Cache/CacheChangeSetEx.cs +++ b/src/DynamicData/Cache/CacheChangeSetEx.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache; internal static class CacheChangeSetEx diff --git a/src/DynamicData/Cache/Change.cs b/src/DynamicData/Cache/Change.cs index 9a0037bdb..3c67f9f73 100644 --- a/src/DynamicData/Cache/Change.cs +++ b/src/DynamicData/Cache/Change.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/ChangeAwareCache.cs b/src/DynamicData/Cache/ChangeAwareCache.cs index 65fd131f1..0ca242365 100644 --- a/src/DynamicData/Cache/ChangeAwareCache.cs +++ b/src/DynamicData/Cache/ChangeAwareCache.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using DynamicData.Cache; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/IGrouping.cs b/src/DynamicData/Cache/IGrouping.cs index d62fb68a9..330bfa375 100644 --- a/src/DynamicData/Cache/IGrouping.cs +++ b/src/DynamicData/Cache/IGrouping.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/IObservableCache.cs b/src/DynamicData/Cache/IObservableCache.cs index aaa73fcb7..1ed3add5c 100644 --- a/src/DynamicData/Cache/IObservableCache.cs +++ b/src/DynamicData/Cache/IObservableCache.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/IQuery.cs b/src/DynamicData/Cache/IQuery.cs index 7e9cebbeb..4d370bbfe 100644 --- a/src/DynamicData/Cache/IQuery.cs +++ b/src/DynamicData/Cache/IQuery.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/IntermediateCache.cs b/src/DynamicData/Cache/IntermediateCache.cs index 3e77eff4d..74cce3c7e 100644 --- a/src/DynamicData/Cache/IntermediateCache.cs +++ b/src/DynamicData/Cache/IntermediateCache.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using DynamicData.Binding; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/Internal/AbstractFilter.cs b/src/DynamicData/Cache/Internal/AbstractFilter.cs index 21b55590a..f0e102eb9 100644 --- a/src/DynamicData/Cache/Internal/AbstractFilter.cs +++ b/src/DynamicData/Cache/Internal/AbstractFilter.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal abstract class AbstractFilter : IFilter diff --git a/src/DynamicData/Cache/Internal/AnonymousObservableCache.cs b/src/DynamicData/Cache/Internal/AnonymousObservableCache.cs index c7f52e597..2f46411b0 100644 --- a/src/DynamicData/Cache/Internal/AnonymousObservableCache.cs +++ b/src/DynamicData/Cache/Internal/AnonymousObservableCache.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Reactive.Disposables; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/AnonymousQuery.cs b/src/DynamicData/Cache/Internal/AnonymousQuery.cs index 22a54cc61..247af24c5 100644 --- a/src/DynamicData/Cache/Internal/AnonymousQuery.cs +++ b/src/DynamicData/Cache/Internal/AnonymousQuery.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class AnonymousQuery(Cache cache) : IQuery diff --git a/src/DynamicData/Cache/Internal/AutoRefresh.cs b/src/DynamicData/Cache/Internal/AutoRefresh.cs index a3f9a7fc1..2288fa849 100644 --- a/src/DynamicData/Cache/Internal/AutoRefresh.cs +++ b/src/DynamicData/Cache/Internal/AutoRefresh.cs @@ -32,7 +32,7 @@ public IObservable> Run() => Observable.Create list.Count > 0).Select(items => new ChangeSet(items)); // publish refreshes and underlying changes - var locker = new object(); + var locker = InternalEx.NewLock(); var publisher = shared.Synchronize(locker).Merge(refreshChanges.Synchronize(locker)).SubscribeSafe(observer); return new CompositeDisposable(publisher, shared.Connect()); diff --git a/src/DynamicData/Cache/Internal/BatchIf.cs b/src/DynamicData/Cache/Internal/BatchIf.cs index 5703567f3..1522b2869 100644 --- a/src/DynamicData/Cache/Internal/BatchIf.cs +++ b/src/DynamicData/Cache/Internal/BatchIf.cs @@ -23,7 +23,7 @@ public IObservable> Run() => Observable.Create { var batchedChanges = new List>(); - var locker = new object(); + var locker = InternalEx.NewLock(); var paused = initialPauseState; var timeoutDisposer = new SerialDisposable(); var intervalTimerDisposer = new SerialDisposable(); diff --git a/src/DynamicData/Cache/Internal/Cache.cs b/src/DynamicData/Cache/Internal/Cache.cs index f4800ad74..3c43c40b6 100644 --- a/src/DynamicData/Cache/Internal/Cache.cs +++ b/src/DynamicData/Cache/Internal/Cache.cs @@ -4,8 +4,6 @@ using System.Diagnostics; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; [DebuggerDisplay("Cache<{typeof(TObject).Name}, {typeof(TKey).Name}> ({Count} Items)")] diff --git a/src/DynamicData/Cache/Internal/CacheUpdater.cs b/src/DynamicData/Cache/Internal/CacheUpdater.cs index f7615436e..103d8bee2 100644 --- a/src/DynamicData/Cache/Internal/CacheUpdater.cs +++ b/src/DynamicData/Cache/Internal/CacheUpdater.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class CacheUpdater : ISourceUpdater diff --git a/src/DynamicData/Cache/Internal/Cast.cs b/src/DynamicData/Cache/Internal/Cast.cs index 296d43562..cf3da7743 100644 --- a/src/DynamicData/Cache/Internal/Cast.cs +++ b/src/DynamicData/Cache/Internal/Cast.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class Cast(IObservable> source, Func converter) diff --git a/src/DynamicData/Cache/Internal/ChangeSetMergeTracker.cs b/src/DynamicData/Cache/Internal/ChangeSetMergeTracker.cs index 697c3f2a5..47360ed68 100644 --- a/src/DynamicData/Cache/Internal/ChangeSetMergeTracker.cs +++ b/src/DynamicData/Cache/Internal/ChangeSetMergeTracker.cs @@ -2,9 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class ChangeSetMergeTracker(Func>> selectCaches, IComparer? comparer, IEqualityComparer? equalityComparer) diff --git a/src/DynamicData/Cache/Internal/Combiner.cs b/src/DynamicData/Cache/Internal/Combiner.cs index 98d7cb2de..6f285c3d5 100644 --- a/src/DynamicData/Cache/Internal/Combiner.cs +++ b/src/DynamicData/Cache/Internal/Combiner.cs @@ -4,8 +4,6 @@ using System.Reactive.Disposables; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; /// @@ -17,7 +15,11 @@ internal sealed class Combiner(CombineOperator type, Action _combinedCache = new(); +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private readonly IList> _sourceCaches = new List>(); diff --git a/src/DynamicData/Cache/Internal/DeferUntilLoaded.cs b/src/DynamicData/Cache/Internal/DeferUntilLoaded.cs index e04e2608b..0dc1a0721 100644 --- a/src/DynamicData/Cache/Internal/DeferUntilLoaded.cs +++ b/src/DynamicData/Cache/Internal/DeferUntilLoaded.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class DeferUntilLoaded diff --git a/src/DynamicData/Cache/Internal/DistinctCalculator.cs b/src/DynamicData/Cache/Internal/DistinctCalculator.cs index 7aa38400d..06e36f8fc 100644 --- a/src/DynamicData/Cache/Internal/DistinctCalculator.cs +++ b/src/DynamicData/Cache/Internal/DistinctCalculator.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class DistinctCalculator(IObservable> source, Func valueSelector) diff --git a/src/DynamicData/Cache/Internal/DynamicCombiner.cs b/src/DynamicData/Cache/Internal/DynamicCombiner.cs index 60514efc5..30ed7b2cb 100644 --- a/src/DynamicData/Cache/Internal/DynamicCombiner.cs +++ b/src/DynamicData/Cache/Internal/DynamicCombiner.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class DynamicCombiner(IObservableList>> source, CombineOperator type) @@ -18,7 +16,7 @@ internal sealed class DynamicCombiner(IObservableList> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // this is the resulting cache which produces all notifications var resultCache = new ChangeAwareCache(); diff --git a/src/DynamicData/Cache/Internal/DynamicFilter.cs b/src/DynamicData/Cache/Internal/DynamicFilter.cs index 2faff65ca..f38526081 100644 --- a/src/DynamicData/Cache/Internal/DynamicFilter.cs +++ b/src/DynamicData/Cache/Internal/DynamicFilter.cs @@ -22,7 +22,7 @@ public IObservable> Run() => Observable.Create(); Func predicate = _ => false; - var locker = new object(); + var locker = InternalEx.NewLock(); var refresher = LatestPredicateObservable().Synchronize(locker).Select( p => diff --git a/src/DynamicData/Cache/Internal/DynamicGrouper.cs b/src/DynamicData/Cache/Internal/DynamicGrouper.cs index 98671a60f..fe0776cd7 100644 --- a/src/DynamicData/Cache/Internal/DynamicGrouper.cs +++ b/src/DynamicData/Cache/Internal/DynamicGrouper.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Reactive.Disposables; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/EditDiff.cs b/src/DynamicData/Cache/Internal/EditDiff.cs index ad7271c42..fecdc3dd1 100644 --- a/src/DynamicData/Cache/Internal/EditDiff.cs +++ b/src/DynamicData/Cache/Internal/EditDiff.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class EditDiff(ISourceCache source, Func areEqual) diff --git a/src/DynamicData/Cache/Internal/EditDiffChangeSet.cs b/src/DynamicData/Cache/Internal/EditDiffChangeSet.cs index d0570b2ec..c7150073c 100644 --- a/src/DynamicData/Cache/Internal/EditDiffChangeSet.cs +++ b/src/DynamicData/Cache/Internal/EditDiffChangeSet.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Reactive.Linq; - namespace DynamicData.Cache.Internal; internal sealed class EditDiffChangeSet(IObservable> source, Func keySelector, IEqualityComparer? equalityComparer) diff --git a/src/DynamicData/Cache/Internal/EditDiffChangeSetOptional.cs b/src/DynamicData/Cache/Internal/EditDiffChangeSetOptional.cs index 702338e94..d68385ec1 100644 --- a/src/DynamicData/Cache/Internal/EditDiffChangeSetOptional.cs +++ b/src/DynamicData/Cache/Internal/EditDiffChangeSetOptional.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/Filter.WithPredicateState.cs b/src/DynamicData/Cache/Internal/Filter.WithPredicateState.cs index c974ed09c..4c465039a 100644 --- a/src/DynamicData/Cache/Internal/Filter.WithPredicateState.cs +++ b/src/DynamicData/Cache/Internal/Filter.WithPredicateState.cs @@ -2,12 +2,7 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System; -using System.Reactive; -using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Transactions; - using DynamicData.Internal; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/FilteredIndexCalculator.cs b/src/DynamicData/Cache/Internal/FilteredIndexCalculator.cs index 159efe8e1..62ab0f192 100644 --- a/src/DynamicData/Cache/Internal/FilteredIndexCalculator.cs +++ b/src/DynamicData/Cache/Internal/FilteredIndexCalculator.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal static class FilteredIndexCalculator diff --git a/src/DynamicData/Cache/Internal/FullJoin.cs b/src/DynamicData/Cache/Internal/FullJoin.cs index ad75bd62b..3a370d2a1 100644 --- a/src/DynamicData/Cache/Internal/FullJoin.cs +++ b/src/DynamicData/Cache/Internal/FullJoin.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class FullJoin(IObservable> left, IObservable> right, Func rightKeySelector, Func, Optional, TDestination> resultSelector) @@ -27,7 +25,7 @@ internal sealed class FullJoin public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); diff --git a/src/DynamicData/Cache/Internal/FullJoinMany.cs b/src/DynamicData/Cache/Internal/FullJoinMany.cs index 77530f4bf..63b7293b3 100644 --- a/src/DynamicData/Cache/Internal/FullJoinMany.cs +++ b/src/DynamicData/Cache/Internal/FullJoinMany.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class FullJoinMany(IObservable> left, IObservable> right, Func rightKeySelector, Func, IGrouping, TDestination> resultSelector) diff --git a/src/DynamicData/Cache/Internal/GroupOn.cs b/src/DynamicData/Cache/Internal/GroupOn.cs index b33734e6c..2ab6b472e 100644 --- a/src/DynamicData/Cache/Internal/GroupOn.cs +++ b/src/DynamicData/Cache/Internal/GroupOn.cs @@ -6,8 +6,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class GroupOn(IObservable> source, Func groupSelectorKey, IObservable? regrouper) @@ -24,7 +22,7 @@ internal sealed class GroupOn(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var grouper = new Grouper(_groupSelectorKey); var groups = _source.Finally(observer.OnCompleted).Synchronize(locker).Select(grouper.Update).Where(changes => changes.Count != 0); diff --git a/src/DynamicData/Cache/Internal/GroupOnDynamic.cs b/src/DynamicData/Cache/Internal/GroupOnDynamic.cs index 04ec7eee2..8cefab3fa 100644 --- a/src/DynamicData/Cache/Internal/GroupOnDynamic.cs +++ b/src/DynamicData/Cache/Internal/GroupOnDynamic.cs @@ -6,7 +6,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using DynamicData.Internal; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/GroupOnImmutable.cs b/src/DynamicData/Cache/Internal/GroupOnImmutable.cs index f6e6ec3a9..283590783 100644 --- a/src/DynamicData/Cache/Internal/GroupOnImmutable.cs +++ b/src/DynamicData/Cache/Internal/GroupOnImmutable.cs @@ -5,8 +5,6 @@ using System.Reactive; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class GroupOnImmutable(IObservable> source, Func groupSelectorKey, IObservable? regrouper) @@ -23,7 +21,7 @@ internal sealed class GroupOnImmutable(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var grouper = new Grouper(_groupSelectorKey); var groups = _source.Synchronize(locker).Select(grouper.Update).Where(changes => changes.Count != 0); diff --git a/src/DynamicData/Cache/Internal/GroupOnObservable.cs b/src/DynamicData/Cache/Internal/GroupOnObservable.cs index 8a3d9c3d6..4ae4df004 100644 --- a/src/DynamicData/Cache/Internal/GroupOnObservable.cs +++ b/src/DynamicData/Cache/Internal/GroupOnObservable.cs @@ -16,7 +16,7 @@ internal sealed class GroupOnObservable(IObservable> Run() => Observable.Create>(observer => { var grouper = new DynamicGrouper(); - var locker = new object(); + var locker = InternalEx.NewLock(); var parentUpdate = false; IObservable CreateGroupObservable(TObject item, TKey key) => diff --git a/src/DynamicData/Cache/Internal/GroupOnProperty.cs b/src/DynamicData/Cache/Internal/GroupOnProperty.cs index dc1b44a9a..45d1fcc30 100644 --- a/src/DynamicData/Cache/Internal/GroupOnProperty.cs +++ b/src/DynamicData/Cache/Internal/GroupOnProperty.cs @@ -6,7 +6,6 @@ using System.Linq.Expressions; using System.Reactive.Concurrency; using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/GroupOnPropertyWithImmutableState.cs b/src/DynamicData/Cache/Internal/GroupOnPropertyWithImmutableState.cs index 5ac4d5ac1..08021f5ee 100644 --- a/src/DynamicData/Cache/Internal/GroupOnPropertyWithImmutableState.cs +++ b/src/DynamicData/Cache/Internal/GroupOnPropertyWithImmutableState.cs @@ -6,7 +6,6 @@ using System.Linq.Expressions; using System.Reactive.Concurrency; using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/ImmutableGroup.cs b/src/DynamicData/Cache/Internal/ImmutableGroup.cs index c6573a371..e4d7557a6 100644 --- a/src/DynamicData/Cache/Internal/ImmutableGroup.cs +++ b/src/DynamicData/Cache/Internal/ImmutableGroup.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class ImmutableGroup : IGrouping, IEquatable> diff --git a/src/DynamicData/Cache/Internal/InnerJoin.cs b/src/DynamicData/Cache/Internal/InnerJoin.cs index f1e769a07..edff85f59 100644 --- a/src/DynamicData/Cache/Internal/InnerJoin.cs +++ b/src/DynamicData/Cache/Internal/InnerJoin.cs @@ -25,7 +25,7 @@ internal sealed class InnerJoin> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); diff --git a/src/DynamicData/Cache/Internal/LeftJoin.cs b/src/DynamicData/Cache/Internal/LeftJoin.cs index e115e0ce2..37e1fa170 100644 --- a/src/DynamicData/Cache/Internal/LeftJoin.cs +++ b/src/DynamicData/Cache/Internal/LeftJoin.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class LeftJoin(IObservable> left, IObservable> right, Func rightKeySelector, Func, TDestination> resultSelector) @@ -27,7 +25,7 @@ internal sealed class LeftJoin public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // create local backing stores var leftShare = _left.Synchronize(locker).Publish(); diff --git a/src/DynamicData/Cache/Internal/LeftJoinMany.cs b/src/DynamicData/Cache/Internal/LeftJoinMany.cs index dfd1a72c1..19ea0c7f0 100644 --- a/src/DynamicData/Cache/Internal/LeftJoinMany.cs +++ b/src/DynamicData/Cache/Internal/LeftJoinMany.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class LeftJoinMany(IObservable> left, IObservable> right, Func rightKeySelector, Func, TDestination> resultSelector) diff --git a/src/DynamicData/Cache/Internal/LockFreeObservableCache.cs b/src/DynamicData/Cache/Internal/LockFreeObservableCache.cs index 5e48a6b5d..c069b5913 100644 --- a/src/DynamicData/Cache/Internal/LockFreeObservableCache.cs +++ b/src/DynamicData/Cache/Internal/LockFreeObservableCache.cs @@ -7,8 +7,6 @@ using System.Reactive.Linq; using System.Reactive.Subjects; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; /// diff --git a/src/DynamicData/Cache/Internal/MergeChangeSets.cs b/src/DynamicData/Cache/Internal/MergeChangeSets.cs index 12ff06f14..041445fdf 100644 --- a/src/DynamicData/Cache/Internal/MergeChangeSets.cs +++ b/src/DynamicData/Cache/Internal/MergeChangeSets.cs @@ -23,7 +23,7 @@ public MergeChangeSets(IEnumerable>> sourc public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var cache = new Cache, int>(); // This is manages all of the changes @@ -41,12 +41,21 @@ public IObservable> Run() => Observable.Create, int> CreateChange(IObservable> source, int index, Lock locker) => + new(ChangeReason.Add, index, new ChangeSetCache(source.Synchronize(locker))); + + // Create a ChangeSet Observable that produces ChangeSets with a single Add event for each new sub-observable + private static IObservable, int>> CreateContainerObservable(IObservable>> source, Lock locker) => + source.Select((src, index) => new ChangeSet, int>(new[] { CreateChange(src, index, locker) })); +#else private static Change, int> CreateChange(IObservable> source, int index, object locker) => new(ChangeReason.Add, index, new ChangeSetCache(source.Synchronize(locker))); // Create a ChangeSet Observable that produces ChangeSets with a single Add event for each new sub-observable private static IObservable, int>> CreateContainerObservable(IObservable>> source, object locker) => source.Select((src, index) => new ChangeSet, int>(new[] { CreateChange(src, index, locker) })); +#endif // Create a ChangeSet Observable with a single event that adds all the values in the enum (and then completes, maybe) private static IObservable>> CreateObservable(IEnumerable>> source, bool completable, IScheduler? scheduler = null) diff --git a/src/DynamicData/Cache/Internal/MergeMany.cs b/src/DynamicData/Cache/Internal/MergeMany.cs index 5f4ce2fab..1cb6fd546 100644 --- a/src/DynamicData/Cache/Internal/MergeMany.cs +++ b/src/DynamicData/Cache/Internal/MergeMany.cs @@ -35,7 +35,7 @@ public IObservable Run() => Observable.Create( observer => { var counter = new SubscriptionCounter(); - var locker = new object(); + var locker = InternalEx.NewLock(); var disposable = _source.Concat(counter.DeferCleanup) .SubscribeMany((t, key) => { diff --git a/src/DynamicData/Cache/Internal/MergeManyCacheChangeSets.cs b/src/DynamicData/Cache/Internal/MergeManyCacheChangeSets.cs index e89636a73..1b704470d 100644 --- a/src/DynamicData/Cache/Internal/MergeManyCacheChangeSets.cs +++ b/src/DynamicData/Cache/Internal/MergeManyCacheChangeSets.cs @@ -20,7 +20,7 @@ internal sealed class MergeManyCacheChangeSets> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var cache = new Cache, TKey>(); var parentUpdate = false; diff --git a/src/DynamicData/Cache/Internal/MergeManyCacheChangeSetsSourceCompare.cs b/src/DynamicData/Cache/Internal/MergeManyCacheChangeSetsSourceCompare.cs index f5907119a..6f0f80e15 100644 --- a/src/DynamicData/Cache/Internal/MergeManyCacheChangeSetsSourceCompare.cs +++ b/src/DynamicData/Cache/Internal/MergeManyCacheChangeSetsSourceCompare.cs @@ -27,7 +27,7 @@ internal sealed class MergeManyCacheChangeSetsSourceCompare> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var cache = new Cache, TKey>(); var parentUpdate = false; diff --git a/src/DynamicData/Cache/Internal/MergeManyItems.cs b/src/DynamicData/Cache/Internal/MergeManyItems.cs index 3282469b7..3fef8f087 100644 --- a/src/DynamicData/Cache/Internal/MergeManyItems.cs +++ b/src/DynamicData/Cache/Internal/MergeManyItems.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class MergeManyItems diff --git a/src/DynamicData/Cache/Internal/MergeManyListChangeSets.cs b/src/DynamicData/Cache/Internal/MergeManyListChangeSets.cs index 7d656cf16..8106a0a5a 100644 --- a/src/DynamicData/Cache/Internal/MergeManyListChangeSets.cs +++ b/src/DynamicData/Cache/Internal/MergeManyListChangeSets.cs @@ -20,7 +20,7 @@ internal sealed class MergeManyListChangeSets(IObse public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var parentUpdate = false; // This is manages all of the changes diff --git a/src/DynamicData/Cache/Internal/ObservableWithValue.cs b/src/DynamicData/Cache/Internal/ObservableWithValue.cs index 6adef008c..ae673f9f5 100644 --- a/src/DynamicData/Cache/Internal/ObservableWithValue.cs +++ b/src/DynamicData/Cache/Internal/ObservableWithValue.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class ObservableWithValue diff --git a/src/DynamicData/Cache/Internal/OfType.cs b/src/DynamicData/Cache/Internal/OfType.cs index c8662afd2..6fb662efd 100644 --- a/src/DynamicData/Cache/Internal/OfType.cs +++ b/src/DynamicData/Cache/Internal/OfType.cs @@ -4,7 +4,6 @@ using System.Reactive.Linq; using DynamicData.Internal; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/OnBeingRemoved.cs b/src/DynamicData/Cache/Internal/OnBeingRemoved.cs index 3e1a24ecc..42e6a2a80 100644 --- a/src/DynamicData/Cache/Internal/OnBeingRemoved.cs +++ b/src/DynamicData/Cache/Internal/OnBeingRemoved.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class OnBeingRemoved(IObservable> source, Action removeAction) @@ -19,7 +17,7 @@ internal sealed class OnBeingRemoved(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var cache = new Cache(); var subscriber = _source.Synchronize(locker).Do(changes => RegisterForRemoval(changes, cache), observer.OnError).SubscribeSafe(observer); diff --git a/src/DynamicData/Cache/Internal/Page.cs b/src/DynamicData/Cache/Internal/Page.cs index a80e597eb..07ab110e0 100644 --- a/src/DynamicData/Cache/Internal/Page.cs +++ b/src/DynamicData/Cache/Internal/Page.cs @@ -13,7 +13,7 @@ internal sealed class Page(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var paginator = new Paginator(); var request = pageRequests.Synchronize(locker).Select(paginator.Paginate); var dataChange = source.Synchronize(locker).Select(paginator.Update); diff --git a/src/DynamicData/Cache/Internal/QueryWhenChanged.cs b/src/DynamicData/Cache/Internal/QueryWhenChanged.cs index 321bd3ded..053eecc05 100644 --- a/src/DynamicData/Cache/Internal/QueryWhenChanged.cs +++ b/src/DynamicData/Cache/Internal/QueryWhenChanged.cs @@ -34,7 +34,7 @@ public IObservable> Run() return _source.Publish( shared => { - var locker = new object(); + var locker = InternalEx.NewLock(); var state = new Cache(); var inlineChange = shared.MergeMany(itemChangedTrigger).Synchronize(locker).Select(_ => new AnonymousQuery(state)); diff --git a/src/DynamicData/Cache/Internal/ReaderWriter.cs b/src/DynamicData/Cache/Internal/ReaderWriter.cs index f7a0debf3..5536b9b0b 100644 --- a/src/DynamicData/Cache/Internal/ReaderWriter.cs +++ b/src/DynamicData/Cache/Internal/ReaderWriter.cs @@ -2,15 +2,17 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class ReaderWriter(Func? keySelector = null) where TObject : notnull where TKey : notnull { +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private CacheUpdater? _activeUpdater; diff --git a/src/DynamicData/Cache/Internal/RefCount.cs b/src/DynamicData/Cache/Internal/RefCount.cs index d9e1fe500..44b964a19 100644 --- a/src/DynamicData/Cache/Internal/RefCount.cs +++ b/src/DynamicData/Cache/Internal/RefCount.cs @@ -11,7 +11,11 @@ internal sealed class RefCount(IObservable> _source = source ?? throw new ArgumentNullException(nameof(source)); diff --git a/src/DynamicData/Cache/Internal/RightJoin.cs b/src/DynamicData/Cache/Internal/RightJoin.cs index 9d7639085..313aff497 100644 --- a/src/DynamicData/Cache/Internal/RightJoin.cs +++ b/src/DynamicData/Cache/Internal/RightJoin.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class RightJoin(IObservable> left, IObservable> right, Func rightKeySelector, Func, TRight, TDestination> resultSelector) @@ -27,7 +25,7 @@ internal sealed class RightJoin> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); diff --git a/src/DynamicData/Cache/Internal/RightJoinMany.cs b/src/DynamicData/Cache/Internal/RightJoinMany.cs index 44879eff5..dea3312c0 100644 --- a/src/DynamicData/Cache/Internal/RightJoinMany.cs +++ b/src/DynamicData/Cache/Internal/RightJoinMany.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class RightJoinMany(IObservable> left, IObservable> right, Func rightKeySelector, Func, IGrouping, TDestination> resultSelector) diff --git a/src/DynamicData/Cache/Internal/SizeExpirer.cs b/src/DynamicData/Cache/Internal/SizeExpirer.cs index 3e4155c58..c4f47055c 100644 --- a/src/DynamicData/Cache/Internal/SizeExpirer.cs +++ b/src/DynamicData/Cache/Internal/SizeExpirer.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class SizeExpirer diff --git a/src/DynamicData/Cache/Internal/SizeLimiter.cs b/src/DynamicData/Cache/Internal/SizeLimiter.cs index 32cba2129..11df5324d 100644 --- a/src/DynamicData/Cache/Internal/SizeLimiter.cs +++ b/src/DynamicData/Cache/Internal/SizeLimiter.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class SizeLimiter(int size) diff --git a/src/DynamicData/Cache/Internal/Sort.cs b/src/DynamicData/Cache/Internal/Sort.cs index ab4101617..a7159a88c 100644 --- a/src/DynamicData/Cache/Internal/Sort.cs +++ b/src/DynamicData/Cache/Internal/Sort.cs @@ -42,7 +42,7 @@ public IObservable> Run() => Observable.Create { var sorter = new Sorter(_sortOptimisations, _comparer, _resetThreshold); - var locker = new object(); + var locker = InternalEx.NewLock(); // check for nulls so we can prevent a lock when not required if (_comparerChangedObservable is null && _resorter is null) diff --git a/src/DynamicData/Cache/Internal/SortAndPage.cs b/src/DynamicData/Cache/Internal/SortAndPage.cs index 5f4e94b47..806c54f11 100644 --- a/src/DynamicData/Cache/Internal/SortAndPage.cs +++ b/src/DynamicData/Cache/Internal/SortAndPage.cs @@ -43,7 +43,7 @@ public IObservable>> Run() => Observable.Create>>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var sortOptions = new SortAndBindOptions { diff --git a/src/DynamicData/Cache/Internal/SortAndVirtualize.cs b/src/DynamicData/Cache/Internal/SortAndVirtualize.cs index 9b6bc5ffd..51509607d 100644 --- a/src/DynamicData/Cache/Internal/SortAndVirtualize.cs +++ b/src/DynamicData/Cache/Internal/SortAndVirtualize.cs @@ -43,7 +43,7 @@ public IObservable>> Run() => Observable.Create>>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var sortOptions = new SortAndBindOptions { diff --git a/src/DynamicData/Cache/Internal/SpecifiedGrouper.cs b/src/DynamicData/Cache/Internal/SpecifiedGrouper.cs index 292e0112d..646cb4eb3 100644 --- a/src/DynamicData/Cache/Internal/SpecifiedGrouper.cs +++ b/src/DynamicData/Cache/Internal/SpecifiedGrouper.cs @@ -21,7 +21,7 @@ internal sealed class SpecifiedGrouper(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // create source group cache var sourceGroups = _source.Synchronize(locker).Group(_groupSelector).DisposeMany().AsObservableCache(); diff --git a/src/DynamicData/Cache/Internal/StatusMonitor.cs b/src/DynamicData/Cache/Internal/StatusMonitor.cs index 8aad491f1..bca5faaed 100644 --- a/src/DynamicData/Cache/Internal/StatusMonitor.cs +++ b/src/DynamicData/Cache/Internal/StatusMonitor.cs @@ -6,8 +6,6 @@ using System.Reactive.Linq; using System.Reactive.Subjects; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class StatusMonitor(IObservable source) diff --git a/src/DynamicData/Cache/Internal/Switch.cs b/src/DynamicData/Cache/Internal/Switch.cs index 58e89c0d5..2c4c9f28e 100644 --- a/src/DynamicData/Cache/Internal/Switch.cs +++ b/src/DynamicData/Cache/Internal/Switch.cs @@ -17,7 +17,7 @@ internal sealed class Switch(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var destination = new LockFreeObservableCache(); diff --git a/src/DynamicData/Cache/Internal/ToObservableOptional.cs b/src/DynamicData/Cache/Internal/ToObservableOptional.cs index 6a3a90f3b..c9c29dc3b 100644 --- a/src/DynamicData/Cache/Internal/ToObservableOptional.cs +++ b/src/DynamicData/Cache/Internal/ToObservableOptional.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; diff --git a/src/DynamicData/Cache/Internal/Transform.cs b/src/DynamicData/Cache/Internal/Transform.cs index b94620e75..7d3c62601 100644 --- a/src/DynamicData/Cache/Internal/Transform.cs +++ b/src/DynamicData/Cache/Internal/Transform.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class Transform(IObservable> source, Func, TKey, TDestination> transformFactory, Action>? exceptionCallback = null, bool transformOnRefresh = false) diff --git a/src/DynamicData/Cache/Internal/TransformAsync.cs b/src/DynamicData/Cache/Internal/TransformAsync.cs index 0e0a4f4b0..271d0184c 100644 --- a/src/DynamicData/Cache/Internal/TransformAsync.cs +++ b/src/DynamicData/Cache/Internal/TransformAsync.cs @@ -4,7 +4,6 @@ using System.Reactive.Linq; using System.Reactive.Threading.Tasks; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; @@ -28,7 +27,7 @@ public IObservable> Run() => if (forceTransform is not null) { - var locker = new object(); + var locker = InternalEx.NewLock(); var forced = forceTransform.Synchronize(locker) .Select(shouldTransform => DoTransform(cache, shouldTransform)).Concat(); diff --git a/src/DynamicData/Cache/Internal/TransformImmutable.cs b/src/DynamicData/Cache/Internal/TransformImmutable.cs index 885270206..1af4840a9 100644 --- a/src/DynamicData/Cache/Internal/TransformImmutable.cs +++ b/src/DynamicData/Cache/Internal/TransformImmutable.cs @@ -5,8 +5,6 @@ using System.Reactive; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class TransformImmutable diff --git a/src/DynamicData/Cache/Internal/TransformMany.cs b/src/DynamicData/Cache/Internal/TransformMany.cs index f8fe8d2b3..45702e4a2 100644 --- a/src/DynamicData/Cache/Internal/TransformMany.cs +++ b/src/DynamicData/Cache/Internal/TransformMany.cs @@ -8,7 +8,6 @@ using System.Reactive.Linq; using DynamicData.Binding; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; @@ -104,7 +103,7 @@ private IObservable> CreateWithChangeS (t, _) => { // Only skip initial for first time Adds where there is initial data records - var locker = new object(); + var locker = InternalEx.NewLock(); var changes = childChanges(t).Synchronize(locker).Skip(1); return new ManyContainer( () => diff --git a/src/DynamicData/Cache/Internal/TransformManyAsync.cs b/src/DynamicData/Cache/Internal/TransformManyAsync.cs index 594187ec2..563e5082e 100644 --- a/src/DynamicData/Cache/Internal/TransformManyAsync.cs +++ b/src/DynamicData/Cache/Internal/TransformManyAsync.cs @@ -6,7 +6,6 @@ using System.Reactive.Linq; using DynamicData.Internal; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; @@ -19,7 +18,7 @@ internal sealed class TransformManyAsync> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var cache = new Cache, TKey>(); var parentUpdate = false; diff --git a/src/DynamicData/Cache/Internal/TransformOnObservable.cs b/src/DynamicData/Cache/Internal/TransformOnObservable.cs index 3e1d85ffd..d9ec3ce08 100644 --- a/src/DynamicData/Cache/Internal/TransformOnObservable.cs +++ b/src/DynamicData/Cache/Internal/TransformOnObservable.cs @@ -16,7 +16,7 @@ internal sealed class TransformOnObservable(IObserv public IObservable> Run() => Observable.Create>(observer => { var cache = new ChangeAwareCache(); - var locker = new object(); + var locker = InternalEx.NewLock(); var parentUpdate = false; // Helper to emit any pending changes when appropriate diff --git a/src/DynamicData/Cache/Internal/TransformWithForcedTransform.cs b/src/DynamicData/Cache/Internal/TransformWithForcedTransform.cs index 116d2dd52..2fc421319 100644 --- a/src/DynamicData/Cache/Internal/TransformWithForcedTransform.cs +++ b/src/DynamicData/Cache/Internal/TransformWithForcedTransform.cs @@ -2,10 +2,8 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.Cache.Internal; @@ -17,7 +15,7 @@ internal sealed class TransformWithForcedTransform( public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var shared = source.Synchronize(locker).Publish(); // capture all items so we can apply a forced transform diff --git a/src/DynamicData/Cache/Internal/TransformWithInlineUpdate.cs b/src/DynamicData/Cache/Internal/TransformWithInlineUpdate.cs index 8efde6da3..99035434f 100644 --- a/src/DynamicData/Cache/Internal/TransformWithInlineUpdate.cs +++ b/src/DynamicData/Cache/Internal/TransformWithInlineUpdate.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class TransformWithInlineUpdate(IObservable> source, diff --git a/src/DynamicData/Cache/Internal/TreeBuilder.cs b/src/DynamicData/Cache/Internal/TreeBuilder.cs index 6f679b9f4..87ed88fc5 100644 --- a/src/DynamicData/Cache/Internal/TreeBuilder.cs +++ b/src/DynamicData/Cache/Internal/TreeBuilder.cs @@ -7,8 +7,6 @@ using System.Reactive.Linq; using System.Reactive.Subjects; -using DynamicData.Kernel; - namespace DynamicData.Cache.Internal; internal sealed class TreeBuilder(IObservable> source, Func pivotOn, IObservable, bool>>? predicateChanged) @@ -26,7 +24,7 @@ internal sealed class TreeBuilder(IObservable, TKey>> Run() => Observable.Create, TKey>>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var reFilterObservable = new BehaviorSubject(Unit.Default); var allData = _source.Synchronize(locker).AsObservableCache(); diff --git a/src/DynamicData/Cache/Internal/Virtualise.cs b/src/DynamicData/Cache/Internal/Virtualise.cs index a0743ef14..a7dccae45 100644 --- a/src/DynamicData/Cache/Internal/Virtualise.cs +++ b/src/DynamicData/Cache/Internal/Virtualise.cs @@ -18,7 +18,7 @@ public IObservable> Run() => Observable.Create< observer => { var virtualiser = new Virtualiser(); - var locker = new object(); + var locker = InternalEx.NewLock(); var request = _virtualRequests.Synchronize(locker).Select(virtualiser.Virtualise).Where(x => x is not null).Select(x => x!); var dataChange = _source.Synchronize(locker).Select(virtualiser.Update).Where(x => x is not null).Select(x => x!); diff --git a/src/DynamicData/Cache/Node.cs b/src/DynamicData/Cache/Node.cs index b1cce171f..fc082f12e 100644 --- a/src/DynamicData/Cache/Node.cs +++ b/src/DynamicData/Cache/Node.cs @@ -4,8 +4,6 @@ using System.Reactive.Disposables; -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/ObservableCache.cs b/src/DynamicData/Cache/ObservableCache.cs index 0ef8fc1cf..7d18f3dbc 100644 --- a/src/DynamicData/Cache/ObservableCache.cs +++ b/src/DynamicData/Cache/ObservableCache.cs @@ -2,16 +2,13 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System; using System.Diagnostics; -using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; using DynamicData.Binding; using DynamicData.Cache; using DynamicData.Cache.Internal; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; @@ -33,7 +30,11 @@ internal sealed class ObservableCache : IObservableCache _suspensionTracker; +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private readonly ReaderWriter _readerWriter; diff --git a/src/DynamicData/Cache/ObservableCacheEx.cs b/src/DynamicData/Cache/ObservableCacheEx.cs index 0fd834542..aa548dbb3 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.cs @@ -12,12 +12,9 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Runtime.CompilerServices; -using DynamicData; using DynamicData.Binding; using DynamicData.Cache; using DynamicData.Cache.Internal; -using DynamicData.Internal; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; @@ -575,7 +572,7 @@ public static IObservable> Bind(this IO return Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); return source.Synchronize(locker).Select( changes => { @@ -703,7 +700,7 @@ public static IObservable> Bind(t return Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); return source.Synchronize(locker).Select( changes => { @@ -4487,7 +4484,7 @@ public static IObservable> ToObservableOptional if (initialOptionalWhenMissing) { var seenValue = false; - var locker = new object(); + var locker = InternalEx.NewLock(); var optional = source.ToObservableOptional(key, equalityComparer).Synchronize(locker).Do(_ => seenValue = true); var missing = Observable.Return(Optional.None()).Synchronize(locker).Where(_ => !seenValue); diff --git a/src/DynamicData/Cache/PageRequest.cs b/src/DynamicData/Cache/PageRequest.cs index da9a70723..a6cb54620 100644 --- a/src/DynamicData/Cache/PageRequest.cs +++ b/src/DynamicData/Cache/PageRequest.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/Cache/SourceCache.cs b/src/DynamicData/Cache/SourceCache.cs index 8d720cbac..1477728c5 100644 --- a/src/DynamicData/Cache/SourceCache.cs +++ b/src/DynamicData/Cache/SourceCache.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using DynamicData.Binding; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/DynamicData.csproj b/src/DynamicData/DynamicData.csproj index cfa6b4d42..b22410df3 100644 --- a/src/DynamicData/DynamicData.csproj +++ b/src/DynamicData/DynamicData.csproj @@ -10,6 +10,10 @@ + + + + Dynamic Data diff --git a/src/DynamicData/EnumerableEx.cs b/src/DynamicData/EnumerableEx.cs index e1576df1c..2459f9a29 100644 --- a/src/DynamicData/EnumerableEx.cs +++ b/src/DynamicData/EnumerableEx.cs @@ -4,7 +4,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Cache.Internal; namespace DynamicData; diff --git a/src/DynamicData/Experimental/Watcher.cs b/src/DynamicData/Experimental/Watcher.cs index bfedbdb54..70ee4a9c6 100644 --- a/src/DynamicData/Experimental/Watcher.cs +++ b/src/DynamicData/Experimental/Watcher.cs @@ -7,8 +7,6 @@ using System.Reactive.Linq; using System.Reactive.Subjects; -using DynamicData.Kernel; - namespace DynamicData.Experimental; internal sealed class Watcher : IWatcher @@ -17,7 +15,11 @@ internal sealed class Watcher : IWatcher { private readonly IDisposable _disposer; +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2213:Disposable fields should be disposed", Justification = "Disposed with _cleanUp")] private readonly IObservableCache _source; diff --git a/src/DynamicData/Internal/Rxx.cs b/src/DynamicData/Internal/Rxx.cs new file mode 100644 index 000000000..d5444716c --- /dev/null +++ b/src/DynamicData/Internal/Rxx.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2011-2023 Roland Pheasant. All rights reserved. +// Roland Pheasant licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +#if NET9_0_OR_GREATER +using DynamicData.Internal; + +namespace System.Reactive.Linq; + +internal static class Rxx +{ + /// + /// Keep this class internal as it should be supplied by System.Reactive and probably will be one day. + /// + public static IObservable Synchronize(this IObservable source, Lock locker) + { + return Observable.Create(observer => + { + return source.SubscribeSafe(t => + { + lock (locker) + { + observer.OnNext(t); + } + }, ex => + { + lock (locker) + { + observer.OnError(ex); + } + }, () => + { + lock (locker) + { + observer.OnCompleted(); + } + }); + }); + } +} +#endif diff --git a/src/DynamicData/Kernel/EnumeratorIList.cs b/src/DynamicData/Kernel/EnumeratorIList.cs index 520799d77..0b16655b7 100644 --- a/src/DynamicData/Kernel/EnumeratorIList.cs +++ b/src/DynamicData/Kernel/EnumeratorIList.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections; -using System.Diagnostics.CodeAnalysis; // Lifted from here https://github.com/benaadams/Ben.Enumerable. Many thanks to the genius of the man. namespace DynamicData.Kernel; diff --git a/src/DynamicData/Kernel/InternalEx.cs b/src/DynamicData/Kernel/InternalEx.cs index 0e70d426d..4929bf69d 100644 --- a/src/DynamicData/Kernel/InternalEx.cs +++ b/src/DynamicData/Kernel/InternalEx.cs @@ -14,6 +14,12 @@ namespace DynamicData.Kernel; /// public static class InternalEx { +#if NET9_0_OR_GREATER + internal static Lock NewLock() => new Lock(); +#else + internal static object NewLock() => new object(); +#endif + /// /// Retries the with back off. /// diff --git a/src/DynamicData/Kernel/OptionExtensions.cs b/src/DynamicData/Kernel/OptionExtensions.cs index f0598a692..e311ecfab 100644 --- a/src/DynamicData/Kernel/OptionExtensions.cs +++ b/src/DynamicData/Kernel/OptionExtensions.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Linq; - namespace DynamicData.Kernel; /// diff --git a/src/DynamicData/Kernel/ParallelEx.cs b/src/DynamicData/Kernel/ParallelEx.cs index e7f364c7b..eb26e42df 100644 --- a/src/DynamicData/Kernel/ParallelEx.cs +++ b/src/DynamicData/Kernel/ParallelEx.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace DynamicData.Kernel; internal static class ParallelEx diff --git a/src/DynamicData/List/Change.cs b/src/DynamicData/List/Change.cs index 179553a2e..7c802e845 100644 --- a/src/DynamicData/List/Change.cs +++ b/src/DynamicData/List/Change.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/List/ChangeAwareList.cs b/src/DynamicData/List/ChangeAwareList.cs index e727e2cc3..7f0625af6 100644 --- a/src/DynamicData/List/ChangeAwareList.cs +++ b/src/DynamicData/List/ChangeAwareList.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections; -using DynamicData.Kernel; namespace DynamicData; diff --git a/src/DynamicData/List/ChangeAwareListWithRefCounts.cs b/src/DynamicData/List/ChangeAwareListWithRefCounts.cs index 2467bc952..cf4a0d689 100644 --- a/src/DynamicData/List/ChangeAwareListWithRefCounts.cs +++ b/src/DynamicData/List/ChangeAwareListWithRefCounts.cs @@ -2,7 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; using DynamicData.List.Internal; // ReSharper disable once CheckNamespace diff --git a/src/DynamicData/List/ChangeSetEx.cs b/src/DynamicData/List/ChangeSetEx.cs index da11c6269..c2655148c 100644 --- a/src/DynamicData/List/ChangeSetEx.cs +++ b/src/DynamicData/List/ChangeSetEx.cs @@ -2,7 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; using DynamicData.List.Internal; using DynamicData.List.Linq; diff --git a/src/DynamicData/List/Internal/AutoRefresh.cs b/src/DynamicData/List/Internal/AutoRefresh.cs index 2304284f6..8bbf2a0c6 100644 --- a/src/DynamicData/List/Internal/AutoRefresh.cs +++ b/src/DynamicData/List/Internal/AutoRefresh.cs @@ -6,8 +6,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class AutoRefresh(IObservable> source, Func> reEvaluator, TimeSpan? buffer = null, IScheduler? scheduler = null) @@ -19,7 +17,7 @@ internal sealed class AutoRefresh(IObservable public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var allItems = new List(); diff --git a/src/DynamicData/List/Internal/BufferIf.cs b/src/DynamicData/List/Internal/BufferIf.cs index 2da8157f9..ea65f9c43 100644 --- a/src/DynamicData/List/Internal/BufferIf.cs +++ b/src/DynamicData/List/Internal/BufferIf.cs @@ -23,7 +23,7 @@ internal sealed class BufferIf(IObservable> source, IObservable public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var paused = initialPauseState; var buffer = new ChangeSet(); var timeoutSubscriber = new SerialDisposable(); diff --git a/src/DynamicData/List/Internal/Combiner.cs b/src/DynamicData/List/Internal/Combiner.cs index de777a870..2912e8442 100644 --- a/src/DynamicData/List/Internal/Combiner.cs +++ b/src/DynamicData/List/Internal/Combiner.cs @@ -12,7 +12,11 @@ namespace DynamicData.List.Internal; internal sealed class Combiner(ICollection>> source, CombineOperator type) where T : notnull { +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private readonly ICollection>> _source = source ?? throw new ArgumentNullException(nameof(source)); diff --git a/src/DynamicData/List/Internal/DeferUntilLoaded.cs b/src/DynamicData/List/Internal/DeferUntilLoaded.cs index 115fd8e88..19f0a39e0 100644 --- a/src/DynamicData/List/Internal/DeferUntilLoaded.cs +++ b/src/DynamicData/List/Internal/DeferUntilLoaded.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class DeferUntilLoaded(IObservable> source) diff --git a/src/DynamicData/List/Internal/Distinct.cs b/src/DynamicData/List/Internal/Distinct.cs index 7287f395b..51daedb4e 100644 --- a/src/DynamicData/List/Internal/Distinct.cs +++ b/src/DynamicData/List/Internal/Distinct.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class Distinct(IObservable> source, Func valueSelector) diff --git a/src/DynamicData/List/Internal/DynamicCombiner.cs b/src/DynamicData/List/Internal/DynamicCombiner.cs index 44daed6be..5b48f9414 100644 --- a/src/DynamicData/List/Internal/DynamicCombiner.cs +++ b/src/DynamicData/List/Internal/DynamicCombiner.cs @@ -6,14 +6,17 @@ using System.Reactive.Linq; using DynamicData.Cache.Internal; -using DynamicData.Kernel; namespace DynamicData.List.Internal; internal sealed class DynamicCombiner(IObservableList>> source, CombineOperator type) where T : notnull { +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private readonly IObservableList>> _source = source ?? throw new ArgumentNullException(nameof(source)); diff --git a/src/DynamicData/List/Internal/EditDiff.cs b/src/DynamicData/List/Internal/EditDiff.cs index 97af3b848..ca5d6081b 100644 --- a/src/DynamicData/List/Internal/EditDiff.cs +++ b/src/DynamicData/List/Internal/EditDiff.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class EditDiff(ISourceList source, IEqualityComparer? equalityComparer) diff --git a/src/DynamicData/List/Internal/Filter.cs b/src/DynamicData/List/Internal/Filter.cs index 79df2e89d..364d43595 100644 --- a/src/DynamicData/List/Internal/Filter.cs +++ b/src/DynamicData/List/Internal/Filter.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class Filter @@ -36,7 +34,7 @@ public Filter(IObservable> source, Func predicate, ListFi public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); Func predicate = _ => false; var all = new List(); diff --git a/src/DynamicData/List/Internal/FilterOnObservable.cs b/src/DynamicData/List/Internal/FilterOnObservable.cs index 30c70843d..3590b7914 100644 --- a/src/DynamicData/List/Internal/FilterOnObservable.cs +++ b/src/DynamicData/List/Internal/FilterOnObservable.cs @@ -17,7 +17,7 @@ internal sealed class FilterOnObservable(IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var allItems = new List(); diff --git a/src/DynamicData/List/Internal/GroupOn.cs b/src/DynamicData/List/Internal/GroupOn.cs index 25855aa18..dd6b768b2 100644 --- a/src/DynamicData/List/Internal/GroupOn.cs +++ b/src/DynamicData/List/Internal/GroupOn.cs @@ -6,8 +6,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class GroupOn(IObservable> source, Func groupSelector, IObservable? regrouper) @@ -29,7 +27,7 @@ public IObservable>> Run() => Observable.C // capture the grouping up front which has the benefit that the group key is only selected once var itemsWithGroup = _source.Transform((t, previous) => new ItemWithGroupKey(t, _groupSelector(t), previous.Convert(p => p.Group)), true); - var locker = new object(); + var locker = InternalEx.NewLock(); var shared = itemsWithGroup.Synchronize(locker).Publish(); var grouper = shared.Select(changes => Process(groupings, groupCache, changes)); diff --git a/src/DynamicData/List/Internal/GroupOnImmutable.cs b/src/DynamicData/List/Internal/GroupOnImmutable.cs index f383c7a7f..1ccd85373 100644 --- a/src/DynamicData/List/Internal/GroupOnImmutable.cs +++ b/src/DynamicData/List/Internal/GroupOnImmutable.cs @@ -6,8 +6,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class GroupOnImmutable(IObservable> source, Func groupSelector, IObservable? reGrouper) @@ -32,7 +30,7 @@ public IObservable>> Run() => Observabl // capture the grouping up front which has the benefit that the group key is only selected once var itemsWithGroup = _source.Transform((t, previous) => new ItemWithGroupKey(t, _groupSelector(t), previous.Convert(p => p.Group)), true); - var locker = new object(); + var locker = InternalEx.NewLock(); var shared = itemsWithGroup.Synchronize(locker).Publish(); var grouper = shared.Select(changes => Process(groupings, groupCache, changes)); diff --git a/src/DynamicData/List/Internal/GroupOnProperty.cs b/src/DynamicData/List/Internal/GroupOnProperty.cs index b98a5b7d9..5b1bda011 100644 --- a/src/DynamicData/List/Internal/GroupOnProperty.cs +++ b/src/DynamicData/List/Internal/GroupOnProperty.cs @@ -7,8 +7,6 @@ using System.Reactive.Concurrency; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class GroupOnProperty(IObservable> source, Expression> groupSelectorKey, TimeSpan? throttle = null, IScheduler? scheduler = null) diff --git a/src/DynamicData/List/Internal/GroupOnPropertyWithImmutableState.cs b/src/DynamicData/List/Internal/GroupOnPropertyWithImmutableState.cs index c85e9731f..29f278b91 100644 --- a/src/DynamicData/List/Internal/GroupOnPropertyWithImmutableState.cs +++ b/src/DynamicData/List/Internal/GroupOnPropertyWithImmutableState.cs @@ -7,8 +7,6 @@ using System.Reactive.Concurrency; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class GroupOnPropertyWithImmutableState(IObservable> source, Expression> groupSelectorKey, TimeSpan? throttle = null, IScheduler? scheduler = null) diff --git a/src/DynamicData/List/Internal/ImmutableGroup.cs b/src/DynamicData/List/Internal/ImmutableGroup.cs index 413ce91d5..c06f1830e 100644 --- a/src/DynamicData/List/Internal/ImmutableGroup.cs +++ b/src/DynamicData/List/Internal/ImmutableGroup.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class ImmutableGroup : IGrouping, IEquatable> diff --git a/src/DynamicData/List/Internal/LimitSizeTo.cs b/src/DynamicData/List/Internal/LimitSizeTo.cs index d8dad320e..8c186d667 100644 --- a/src/DynamicData/List/Internal/LimitSizeTo.cs +++ b/src/DynamicData/List/Internal/LimitSizeTo.cs @@ -7,7 +7,12 @@ namespace DynamicData.List.Internal; +#if NET9_0_OR_GREATER +internal sealed class LimitSizeTo(ISourceList sourceList, int sizeLimit, IScheduler scheduler, Lock locker) +#else internal sealed class LimitSizeTo(ISourceList sourceList, int sizeLimit, IScheduler scheduler, object locker) +#endif + where T : notnull { private readonly IScheduler _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); diff --git a/src/DynamicData/List/Internal/MergeChangeSets.cs b/src/DynamicData/List/Internal/MergeChangeSets.cs index eb89e96df..91be5634b 100644 --- a/src/DynamicData/List/Internal/MergeChangeSets.cs +++ b/src/DynamicData/List/Internal/MergeChangeSets.cs @@ -21,7 +21,7 @@ public MergeChangeSets(IEnumerable>> source, IEq public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); // This is manages all of the changes var changeTracker = new ChangeSetMergeTracker(); @@ -49,10 +49,20 @@ private static IObservable>> CreateObservable(IE } // Can optimize for the Add case because that's the only one that applies +#if NET9_0_OR_GREATER + private Change> CreateChange(IObservable> source, Lock locker) => + new(ListChangeReason.Add, new ClonedListChangeSet(source.Synchronize(locker), equalityComparer)); + + // Create a ChangeSet Observable that produces ChangeSets with a single Add event for each new sub-observable + private IObservable>> CreateClonedListObservable(IObservable>> source, Lock locker) => + source.Select(src => new ChangeSet>(new[] { CreateChange(src, locker) })); +#else private Change> CreateChange(IObservable> source, object locker) => new(ListChangeReason.Add, new ClonedListChangeSet(source.Synchronize(locker), equalityComparer)); // Create a ChangeSet Observable that produces ChangeSets with a single Add event for each new sub-observable private IObservable>> CreateClonedListObservable(IObservable>> source, object locker) => source.Select(src => new ChangeSet>(new[] { CreateChange(src, locker) })); +#endif + } diff --git a/src/DynamicData/List/Internal/MergeMany.cs b/src/DynamicData/List/Internal/MergeMany.cs index c3bc722c3..918bddb09 100644 --- a/src/DynamicData/List/Internal/MergeMany.cs +++ b/src/DynamicData/List/Internal/MergeMany.cs @@ -19,7 +19,7 @@ public IObservable Run() => Observable.Create( observer => { var counter = new SubscriptionCounter(); - var locker = new object(); + var locker = InternalEx.NewLock(); var disposable = _source.Concat(counter.DeferCleanup) .SubscribeMany(t => { diff --git a/src/DynamicData/List/Internal/MergeManyCacheChangeSets.cs b/src/DynamicData/List/Internal/MergeManyCacheChangeSets.cs index 074443613..5c54925dc 100644 --- a/src/DynamicData/List/Internal/MergeManyCacheChangeSets.cs +++ b/src/DynamicData/List/Internal/MergeManyCacheChangeSets.cs @@ -20,7 +20,7 @@ internal sealed class MergeManyCacheChangeSets> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var list = new List>(); var parentUpdate = false; diff --git a/src/DynamicData/List/Internal/MergeManyListChangeSets.cs b/src/DynamicData/List/Internal/MergeManyListChangeSets.cs index b7a3a4fe7..99c24b383 100644 --- a/src/DynamicData/List/Internal/MergeManyListChangeSets.cs +++ b/src/DynamicData/List/Internal/MergeManyListChangeSets.cs @@ -18,7 +18,7 @@ internal sealed class MergeManyListChangeSets(IObservable public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var parentUpdate = false; // This is manages all of the changes diff --git a/src/DynamicData/List/Internal/OnBeingAdded.cs b/src/DynamicData/List/Internal/OnBeingAdded.cs index 051fe45fd..b8e065fc7 100644 --- a/src/DynamicData/List/Internal/OnBeingAdded.cs +++ b/src/DynamicData/List/Internal/OnBeingAdded.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class OnBeingAdded(IObservable> source, Action callback) diff --git a/src/DynamicData/List/Internal/OnBeingRemoved.cs b/src/DynamicData/List/Internal/OnBeingRemoved.cs index e21a1fd8a..dfae92ef9 100644 --- a/src/DynamicData/List/Internal/OnBeingRemoved.cs +++ b/src/DynamicData/List/Internal/OnBeingRemoved.cs @@ -5,8 +5,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class OnBeingRemoved(IObservable> source, Action callback, bool invokeOnUnsubscribe) @@ -18,7 +16,7 @@ internal sealed class OnBeingRemoved(IObservable> source, Actio public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var items = new List(); var subscriber = _source.Synchronize(locker).Do(changes => RegisterForRemoval(items, changes), observer.OnError).SubscribeSafe(observer); diff --git a/src/DynamicData/List/Internal/Pager.cs b/src/DynamicData/List/Internal/Pager.cs index 6a53a4bb1..041d4fcce 100644 --- a/src/DynamicData/List/Internal/Pager.cs +++ b/src/DynamicData/List/Internal/Pager.cs @@ -17,7 +17,7 @@ internal sealed class Pager(IObservable> source, IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var all = new List(); var paged = new ChangeAwareList(); diff --git a/src/DynamicData/List/Internal/QueryWhenChanged.cs b/src/DynamicData/List/Internal/QueryWhenChanged.cs index 54ac665f6..0336f51db 100644 --- a/src/DynamicData/List/Internal/QueryWhenChanged.cs +++ b/src/DynamicData/List/Internal/QueryWhenChanged.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class QueryWhenChanged(IObservable> source) diff --git a/src/DynamicData/List/Internal/ReaderWriter.cs b/src/DynamicData/List/Internal/ReaderWriter.cs index 222eea63b..83f36f3fc 100644 --- a/src/DynamicData/List/Internal/ReaderWriter.cs +++ b/src/DynamicData/List/Internal/ReaderWriter.cs @@ -2,14 +2,16 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class ReaderWriter where T : notnull { +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private ChangeAwareList _data = new(); diff --git a/src/DynamicData/List/Internal/RefCount.cs b/src/DynamicData/List/Internal/RefCount.cs index ee9f75d47..e3aeb7e00 100644 --- a/src/DynamicData/List/Internal/RefCount.cs +++ b/src/DynamicData/List/Internal/RefCount.cs @@ -10,7 +10,11 @@ namespace DynamicData.List.Internal; internal sealed class RefCount(IObservable> source) where T : notnull { +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private IObservableList? _list; private int _refCount; diff --git a/src/DynamicData/List/Internal/Sort.cs b/src/DynamicData/List/Internal/Sort.cs index ba0abc39e..0e1a1338a 100644 --- a/src/DynamicData/List/Internal/Sort.cs +++ b/src/DynamicData/List/Internal/Sort.cs @@ -5,8 +5,6 @@ using System.Reactive; using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class Sort(IObservable> source, IComparer? comparer, SortOptions sortOptions, IObservable? resort, IObservable>? comparerObservable, int resetThreshold) @@ -21,7 +19,7 @@ internal sealed class Sort(IObservable> source, IComparer? c public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var original = new List(); var target = new ChangeAwareList(); diff --git a/src/DynamicData/List/Internal/Switch.cs b/src/DynamicData/List/Internal/Switch.cs index b1ccc76f9..f95fb2f4b 100644 --- a/src/DynamicData/List/Internal/Switch.cs +++ b/src/DynamicData/List/Internal/Switch.cs @@ -15,7 +15,7 @@ internal sealed class Switch(IObservable>> sources) public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var destination = new SourceList(); diff --git a/src/DynamicData/List/Internal/TransformAsync.cs b/src/DynamicData/List/Internal/TransformAsync.cs index c1b8daa5f..87b833b6a 100644 --- a/src/DynamicData/List/Internal/TransformAsync.cs +++ b/src/DynamicData/List/Internal/TransformAsync.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.List.Internal; diff --git a/src/DynamicData/List/Internal/TransformMany.cs b/src/DynamicData/List/Internal/TransformMany.cs index 6993b8be5..e595b7caf 100644 --- a/src/DynamicData/List/Internal/TransformMany.cs +++ b/src/DynamicData/List/Internal/TransformMany.cs @@ -8,7 +8,6 @@ using System.Reactive.Linq; using DynamicData.Binding; -using DynamicData.Kernel; namespace DynamicData.List.Internal; @@ -117,7 +116,7 @@ private IObservable> CreateWithChangeSet() var transformed = _source.Transform( t => { - var locker = new object(); + var locker = InternalEx.NewLock(); var collection = manySelector(t); var changes = childChanges(t).Synchronize(locker).Skip(1); return new ManyContainer(collection, changes); diff --git a/src/DynamicData/List/Internal/Transformer.cs b/src/DynamicData/List/Internal/Transformer.cs index d43c18d3b..ce1634b03 100644 --- a/src/DynamicData/List/Internal/Transformer.cs +++ b/src/DynamicData/List/Internal/Transformer.cs @@ -4,8 +4,6 @@ using System.Reactive.Linq; -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal sealed class Transformer diff --git a/src/DynamicData/List/Internal/UnifiedChange.cs b/src/DynamicData/List/Internal/UnifiedChange.cs index 1ca53ab5d..085ca6fd3 100644 --- a/src/DynamicData/List/Internal/UnifiedChange.cs +++ b/src/DynamicData/List/Internal/UnifiedChange.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - namespace DynamicData.List.Internal; internal readonly struct UnifiedChange(ListChangeReason reason, T current, Optional previous) : IEquatable> diff --git a/src/DynamicData/List/Internal/Virtualiser.cs b/src/DynamicData/List/Internal/Virtualiser.cs index 4025fdb1c..2e352230f 100644 --- a/src/DynamicData/List/Internal/Virtualiser.cs +++ b/src/DynamicData/List/Internal/Virtualiser.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Reactive.Linq; -using DynamicData.Kernel; namespace DynamicData.List.Internal; @@ -17,7 +16,7 @@ internal sealed class Virtualiser(IObservable> source, IObserva public IObservable> Run() => Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); var all = new List(); var virtualised = new ChangeAwareList(); diff --git a/src/DynamicData/List/ItemChange.cs b/src/DynamicData/List/ItemChange.cs index 9432da5b7..c71936984 100644 --- a/src/DynamicData/List/ItemChange.cs +++ b/src/DynamicData/List/ItemChange.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/List/ListEx.cs b/src/DynamicData/List/ListEx.cs index f6e8bbf74..11747228e 100644 --- a/src/DynamicData/List/ListEx.cs +++ b/src/DynamicData/List/ListEx.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for full license information. using System.Collections.ObjectModel; -using System.ComponentModel; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 4a24a45c3..8c444da48 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -10,11 +10,8 @@ using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; - -using DynamicData; using DynamicData.Binding; using DynamicData.Cache.Internal; -using DynamicData.Kernel; using DynamicData.List.Internal; using DynamicData.List.Linq; @@ -47,7 +44,7 @@ public static IObservable> Adapt(this IObservable return Observable.Create>( observer => { - var locker = new object(); + var locker = InternalEx.NewLock(); return source.Synchronize(locker).Select( changes => { @@ -948,7 +945,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou throw new ArgumentException("sizeLimit cannot be zero", nameof(sizeLimit)); } - var locker = new object(); + var locker = InternalEx.NewLock(); var limiter = new LimitSizeTo(source, sizeLimit, scheduler ?? GlobalConfig.DefaultScheduler, locker); return limiter.Run().Synchronize(locker).Do(source.RemoveMany); diff --git a/src/DynamicData/List/RangeChange.cs b/src/DynamicData/List/RangeChange.cs index 8ab9c33f1..5df0fa704 100644 --- a/src/DynamicData/List/RangeChange.cs +++ b/src/DynamicData/List/RangeChange.cs @@ -4,8 +4,6 @@ using System.Collections; -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData; diff --git a/src/DynamicData/List/SortOptions.cs b/src/DynamicData/List/SortOptions.cs index 73a546e37..c8625056a 100644 --- a/src/DynamicData/List/SortOptions.cs +++ b/src/DynamicData/List/SortOptions.cs @@ -2,8 +2,6 @@ // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - namespace DynamicData; /// diff --git a/src/DynamicData/List/SourceList.cs b/src/DynamicData/List/SourceList.cs index 744442771..ad21d900b 100644 --- a/src/DynamicData/List/SourceList.cs +++ b/src/DynamicData/List/SourceList.cs @@ -28,7 +28,11 @@ public sealed class SourceList : ISourceList private readonly Lazy> _countChanged = new(() => new Subject()); +#if NET9_0_OR_GREATER + private readonly Lock _locker = new(); +#else private readonly object _locker = new(); +#endif private readonly ReaderWriter _readerWriter = new(); diff --git a/src/DynamicData/ObservableChangeSet.cs b/src/DynamicData/ObservableChangeSet.cs index a67a9c1e3..9ac6646f6 100644 --- a/src/DynamicData/ObservableChangeSet.cs +++ b/src/DynamicData/ObservableChangeSet.cs @@ -4,7 +4,6 @@ using System.Reactive.Disposables; using System.Reactive.Linq; -using DynamicData.Cache.Internal; namespace DynamicData; diff --git a/src/DynamicData/Platforms/net45/PFilter.cs b/src/DynamicData/Platforms/net45/PFilter.cs index 97887fe88..c7ef258f7 100644 --- a/src/DynamicData/Platforms/net45/PFilter.cs +++ b/src/DynamicData/Platforms/net45/PFilter.cs @@ -6,7 +6,6 @@ using System.Reactive.Linq; using DynamicData.Cache.Internal; -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData.PLinq diff --git a/src/DynamicData/Platforms/net45/PTransform.cs b/src/DynamicData/Platforms/net45/PTransform.cs index 1c5fe05cb..a234965a0 100644 --- a/src/DynamicData/Platforms/net45/PTransform.cs +++ b/src/DynamicData/Platforms/net45/PTransform.cs @@ -5,8 +5,6 @@ #if P_LINQ using System.Reactive.Linq; -using DynamicData.Kernel; - // ReSharper disable once CheckNamespace namespace DynamicData.PLinq { diff --git a/src/DynamicData/Platforms/net45/ParallelOperators.cs b/src/DynamicData/Platforms/net45/ParallelOperators.cs index bc47c0ea6..eda3bc6e5 100644 --- a/src/DynamicData/Platforms/net45/ParallelOperators.cs +++ b/src/DynamicData/Platforms/net45/ParallelOperators.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for full license information. #if P_LINQ -using DynamicData.Kernel; // ReSharper disable once CheckNamespace namespace DynamicData.PLinq