-
-
Notifications
You must be signed in to change notification settings - Fork 192
Split ObservableCacheEx.cs into per-family partial classes #1095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
dwcullop
merged 11 commits into
reactivemarbles:main
from
dwcullop:maint/cache_ext_breakup
Jun 6, 2026
Merged
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f80163c
Break ObservableCacheEx.cs into per-family partial classes
dwcullop 2a38ed0
Break ObservableCacheEx.cs into per-family partial classes
dwcullop 3d5ae4b
Merge old maint/cache_ext_breakup (pre-#1079 split) into rebased split
dwcullop 87759e8
Alphabetize members within new ObservableCacheEx partial files
dwcullop 1d6e6c0
Merge branch 'main' into maint/cache_ext_breakup
dwcullop 70b7a00
Merge branch 'main' into maint/cache_ext_breakup
dwcullop 6ddc45b
Merge branch 'main' into maint/cache_ext_breakup
dwcullop 22160a5
Merge branch 'main' into maint/cache_ext_breakup
dwcullop afec94f
Split ObservableCacheEx.cs partials into one file per operator (overl…
dwcullop 9dddce3
Extract shared private helpers into per-helper partial files
dwcullop be700ab
Merge branch 'main' into maint/cache_ext_breakup
dwcullop File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // Copyright (c) 2011-2025 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. | ||
|
|
||
| using System.Collections.ObjectModel; | ||
| using System.Collections.Specialized; | ||
| using System.ComponentModel; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq.Expressions; | ||
| using System.Reactive; | ||
| using System.Reactive.Concurrency; | ||
| using System.Reactive.Disposables; | ||
| using System.Reactive.Linq; | ||
| using System.Runtime.CompilerServices; | ||
| using DynamicData.Binding; | ||
| using DynamicData.Cache; | ||
| using DynamicData.Cache.Internal; | ||
|
|
||
| // ReSharper disable once CheckNamespace | ||
|
|
||
| namespace DynamicData; | ||
|
|
||
| /// <summary> | ||
| /// ObservableCache extensions for Adapt. | ||
| /// </summary> | ||
| public static partial class ObservableCacheEx | ||
| { | ||
| /// <summary> | ||
| /// Injects a side effect into the changeset stream by calling <paramref name="adaptor"/>.<see cref="IChangeSetAdaptor{TObject, TKey}.Adapt(IChangeSet{TObject, TKey})"/> | ||
| /// for every changeset, then forwarding it downstream unchanged. | ||
| /// </summary> | ||
| /// <typeparam name="TObject">The type of items in the cache.</typeparam> | ||
| /// <typeparam name="TKey">The type of the key.</typeparam> | ||
| /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to observe and adapt.</param> | ||
| /// <param name="adaptor">The <see cref="IChangeSetAdaptor{TObject, TKey}"/> whose Adapt method is called for each changeset.</param> | ||
| /// <returns>An observable that emits the same changesets as <paramref name="source"/>, after the adaptor has processed each one.</returns> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// This is a thin wrapper around Rx's <c>Do</c> operator. The adaptor receives each changeset | ||
| /// as a side effect; the changeset itself is forwarded downstream unmodified. | ||
| /// </para> | ||
| /// </remarks> | ||
| /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="adaptor"/> is <see langword="null"/>.</exception> | ||
| /// <seealso cref="Adapt{TObject, TKey}(IObservable{ISortedChangeSet{TObject, TKey}}, ISortedChangeSetAdaptor{TObject, TKey})"/> | ||
| /// <seealso cref="Bind{TObject, TKey}(IObservable{IChangeSet{TObject, TKey}}, IObservableCollection{TObject}, IObservableCollectionAdaptor{TObject, TKey})"/> | ||
| public static IObservable<IChangeSet<TObject, TKey>> Adapt<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, IChangeSetAdaptor<TObject, TKey> adaptor) | ||
| where TObject : notnull | ||
| where TKey : notnull | ||
| { | ||
| source.ThrowArgumentNullExceptionIfNull(nameof(source)); | ||
| adaptor.ThrowArgumentNullExceptionIfNull(nameof(adaptor)); | ||
|
|
||
| return source.Do(adaptor.Adapt); | ||
| } | ||
|
|
||
| /// <inheritdoc cref="Adapt{TObject, TKey}(IObservable{IChangeSet{TObject, TKey}}, IChangeSetAdaptor{TObject, TKey})"/> | ||
| /// <param name="source">The source <see cref="IObservable{ISortedChangeSet{TObject, TKey}}"/> to observe and adapt.</param> | ||
| /// <param name="adaptor">The <see cref="ISortedChangeSetAdaptor{TObject, TKey}"/> whose Adapt method is called for each changeset.</param> | ||
| /// <remarks>This overload operates on <see cref="ISortedChangeSet{TObject, TKey}"/>. Delegates to Rx's <c>Do</c> operator.</remarks> | ||
| public static IObservable<IChangeSet<TObject, TKey>> Adapt<TObject, TKey>(this IObservable<ISortedChangeSet<TObject, TKey>> source, ISortedChangeSetAdaptor<TObject, TKey> adaptor) | ||
| where TObject : notnull | ||
| where TKey : notnull | ||
| { | ||
| source.ThrowArgumentNullExceptionIfNull(nameof(source)); | ||
| adaptor.ThrowArgumentNullExceptionIfNull(nameof(adaptor)); | ||
|
|
||
| return source.Do(adaptor.Adapt); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| // Copyright (c) 2011-2025 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. | ||
|
|
||
| using System.Collections.ObjectModel; | ||
| using System.Collections.Specialized; | ||
| using System.ComponentModel; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq.Expressions; | ||
| using System.Reactive; | ||
| using System.Reactive.Concurrency; | ||
| using System.Reactive.Disposables; | ||
| using System.Reactive.Linq; | ||
| using System.Runtime.CompilerServices; | ||
| using DynamicData.Binding; | ||
| using DynamicData.Cache; | ||
| using DynamicData.Cache.Internal; | ||
|
|
||
| // ReSharper disable once CheckNamespace | ||
|
|
||
| namespace DynamicData; | ||
|
|
||
| /// <summary> | ||
| /// ObservableCache extensions for AutoRefresh. | ||
| /// </summary> | ||
| public static partial class ObservableCacheEx | ||
| { | ||
| /// <summary> | ||
| /// Automatically refresh downstream operators when any properties change. | ||
| /// </summary> | ||
| /// <typeparam name="TObject">The object of the change set.</typeparam> | ||
| /// <typeparam name="TKey">The key of the change set.</typeparam> | ||
| /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to monitor for property-driven refresh signals.</param> | ||
| /// <param name="changeSetBuffer">An optional <see cref="TimeSpan"/> buffer duration. Batches multiple refresh signals into a single changeset, improving performance when many elements change in quick succession. This greatly increases performance when many elements have successive property changes.</param> | ||
| /// <param name="propertyChangeThrottle">An optional <see cref="TimeSpan"/> throttle applied to each item's property change notifications, preventing excessive refresh invocations.</param> | ||
| /// <param name="scheduler">An optional <see cref="IScheduler"/> for scheduling work.</param> | ||
| /// <returns>An observable change set with additional refresh changes.</returns> | ||
| /// <seealso cref="ObservableListEx.AutoRefresh"/> | ||
| public static IObservable<IChangeSet<TObject, TKey>> AutoRefresh<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) | ||
| where TObject : INotifyPropertyChanged | ||
| where TKey : notnull | ||
| { | ||
| source.ThrowArgumentNullExceptionIfNull(nameof(source)); | ||
|
|
||
| return source.AutoRefreshOnObservable( | ||
| (t, _) => | ||
| { | ||
| if (propertyChangeThrottle is null) | ||
| { | ||
| return t.WhenAnyPropertyChanged(); | ||
| } | ||
|
|
||
| return t.WhenAnyPropertyChanged().Throttle(propertyChangeThrottle.Value, scheduler ?? GlobalConfig.DefaultScheduler); | ||
| }, | ||
| changeSetBuffer, | ||
| scheduler); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Automatically refresh downstream operators when properties change. | ||
| /// </summary> | ||
| /// <typeparam name="TObject">The object of the change set.</typeparam> | ||
| /// <typeparam name="TKey">The key of the change set.</typeparam> | ||
| /// <typeparam name="TProperty">The type of the property.</typeparam> | ||
| /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to monitor for property-driven refresh signals.</param> | ||
| /// <param name="propertyAccessor">A <see cref="Expression{TDelegate}"/> that specify a property to observe changes. When it changes a Refresh is invoked.</param> | ||
| /// <param name="changeSetBuffer">An optional <see cref="TimeSpan"/> buffer duration. Batches multiple refresh signals into a single changeset, improving performance when many elements change in quick succession. This greatly increases performance when many elements have successive property changes.</param> | ||
| /// <param name="propertyChangeThrottle">An optional <see cref="TimeSpan"/> throttle applied to each item's property change notifications, preventing excessive refresh invocations.</param> | ||
| /// <param name="scheduler">An optional <see cref="IScheduler"/> for scheduling work.</param> | ||
| /// <returns>An observable change set with additional refresh changes.</returns> | ||
| public static IObservable<IChangeSet<TObject, TKey>> AutoRefresh<TObject, TKey, TProperty>(this IObservable<IChangeSet<TObject, TKey>> source, Expression<Func<TObject, TProperty>> propertyAccessor, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) | ||
| where TObject : INotifyPropertyChanged | ||
| where TKey : notnull | ||
| { | ||
| source.ThrowArgumentNullExceptionIfNull(nameof(source)); | ||
|
|
||
| return source.AutoRefreshOnObservable( | ||
| (t, _) => | ||
| { | ||
| if (propertyChangeThrottle is null) | ||
| { | ||
| return t.WhenPropertyChanged(propertyAccessor, false); | ||
| } | ||
|
|
||
| return t.WhenPropertyChanged(propertyAccessor, false).Throttle(propertyChangeThrottle.Value, scheduler ?? GlobalConfig.DefaultScheduler); | ||
| }, | ||
| changeSetBuffer, | ||
| scheduler); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Automatically refresh downstream operator. The refresh is triggered when the observable receives a notification. | ||
| /// </summary> | ||
| /// <typeparam name="TObject">The object of the change set.</typeparam> | ||
| /// <typeparam name="TKey">The key of the change set.</typeparam> | ||
| /// <typeparam name="TAny">The type of evaluation.</typeparam> | ||
| /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to monitor for observable-driven refresh signals.</param> | ||
| /// <param name="reevaluator">The <see cref="Func{TObject, IObservable{TAny}}"/> observable which acts on items within the collection and produces a value when the item should be refreshed.</param> | ||
| /// <param name="changeSetBuffer">An optional <see cref="TimeSpan"/> buffer duration. Batches multiple refresh signals into a single changeset, improving performance when many elements change in quick succession. This greatly increases performance when many elements require a refresh.</param> | ||
| /// <param name="scheduler">An optional <see cref="IScheduler"/> for scheduling work.</param> | ||
| /// <returns>An observable change set with additional refresh changes.</returns> | ||
| /// <seealso cref="ObservableListEx.AutoRefreshOnObservable"/> | ||
| public static IObservable<IChangeSet<TObject, TKey>> AutoRefreshOnObservable<TObject, TKey, TAny>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, IObservable<TAny>> reevaluator, TimeSpan? changeSetBuffer = null, IScheduler? scheduler = null) | ||
| where TObject : notnull | ||
| where TKey : notnull => source.AutoRefreshOnObservable((t, _) => reevaluator(t), changeSetBuffer, scheduler); | ||
|
|
||
| /// <summary> | ||
| /// Automatically refresh downstream operator. The refresh is triggered when the observable receives a notification. | ||
| /// </summary> | ||
| /// <typeparam name="TObject">The object of the change set.</typeparam> | ||
| /// <typeparam name="TKey">The key of the change set.</typeparam> | ||
| /// <typeparam name="TAny">The type of evaluation.</typeparam> | ||
| /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to monitor for observable-driven refresh signals.</param> | ||
| /// <param name="reevaluator">The <see cref="Func{TObject, TKey, IObservable{TAny}}"/> observable which acts on items within the collection and produces a value when the item should be refreshed.</param> | ||
| /// <param name="changeSetBuffer">An optional <see cref="TimeSpan"/> buffer duration. Batches multiple refresh signals into a single changeset, improving performance when many elements change in quick succession. This greatly increases performance when many elements require a refresh.</param> | ||
| /// <param name="scheduler">An optional <see cref="IScheduler"/> for scheduling work.</param> | ||
| /// <returns>An observable change set with additional refresh changes.</returns> | ||
| /// <remarks> | ||
| /// <para><b>Worth noting:</b> Per-item observable errors are silently ignored (not forwarded to the downstream observer). Only source stream errors propagate.</para> | ||
| /// </remarks> | ||
| public static IObservable<IChangeSet<TObject, TKey>> AutoRefreshOnObservable<TObject, TKey, TAny>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, TKey, IObservable<TAny>> reevaluator, TimeSpan? changeSetBuffer = null, IScheduler? scheduler = null) | ||
| where TObject : notnull | ||
| where TKey : notnull | ||
| { | ||
| source.ThrowArgumentNullExceptionIfNull(nameof(source)); | ||
| reevaluator.ThrowArgumentNullExceptionIfNull(nameof(reevaluator)); | ||
|
|
||
| return new AutoRefresh<TObject, TKey, TAny>(source, reevaluator, changeSetBuffer, scheduler).Run(); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.