diff --git a/src/Uno.Extensions.Reactive.Tests/Operators/Given_StateForEach.cs b/src/Uno.Extensions.Reactive.Tests/Operators/Given_StateForEach.cs index 1ebde035db..8eca06ce53 100644 --- a/src/Uno.Extensions.Reactive.Tests/Operators/Given_StateForEach.cs +++ b/src/Uno.Extensions.Reactive.Tests/Operators/Given_StateForEach.cs @@ -43,13 +43,13 @@ public async Task When_ForEachAsync_Then_AcceptsNotNullAndStruct() public async Task When_ForEachDataAsync_Then_AcceptsNotNullAndStruct() { _ = default(IState)!.ForEach(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); - default(IState)!.ForEachDataAsync(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); + _ = default(IState)!.ForEachData(async (i, ct) => this.ToString()); } [TestMethod] diff --git a/src/Uno.Extensions.Reactive/Core/State.Extensions.cs b/src/Uno.Extensions.Reactive/Core/State.Extensions.cs index 726e2f4a94..9e93e4eead 100644 --- a/src/Uno.Extensions.Reactive/Core/State.Extensions.cs +++ b/src/Uno.Extensions.Reactive/Core/State.Extensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; @@ -287,6 +287,16 @@ public static IState ForEach(this IState state, AsyncAction action, } + /// + /// [DEPRECATED] Use ForEachData instead + /// + [EditorBrowsable(EditorBrowsableState.Never)] +#if DEBUG // To avoid usage in internal reactive code, but without forcing apps to update right away + [Obsolete("Use ForEachData")] +#endif + public static IDisposable ForEachDataAsync(this IState state, AsyncAction> action, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = -1) + => new StateForEach(state, action, $"ForEachDataAsync defined in {caller} at line {line}."); + /// /// Execute an async callback each time the state is being updated. /// @@ -294,10 +304,39 @@ public static IState ForEach(this IState state, AsyncAction action, /// The state to listen. /// The callback to invoke on each update of the state. /// For debug purposes, the name of this subscription. DO NOT provide anything here, let the compiler fulfill this. - /// For debug purposes, the name of this subscription. DO NOT provide anything here, let the compiler fulfill this. - /// A that can be used to remove the callback registration. - public static IDisposable ForEachDataAsync(this IState state, AsyncAction> action, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = -1) - => new StateForEach(state, action, $"ForEachDataAsync defined in {caller} at line {line}."); + /// For debug purposes, the name of this subscription. DO NOT provide anything here, let the compiler fulfill this. + /// An that can be used to chain other operations. + public static IState ForEachData(this IState state, AsyncAction> action, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = -1) + { + _ = AttachedProperty.GetOrCreate( + owner: state, + key: action, + state: (caller, line), + factory: static (s, a, d) => new StateForEach(s, a, $"ForEachData defined in {d.caller} at line {d.line}.")); + + return state; + } + + /// + /// Execute an async callback each time the state is being updated. + /// + /// The type of the state + /// The state to listen. + /// The callback to invoke on each update of the state. + /// A that can be used to remove the callback registration. + /// For debug purposes, the name of this subscription. DO NOT provide anything here, let the compiler fulfill this. + /// For debug purposes, the name of this subscription. DO NOT provide anything here, let the compiler fulfill this. + /// An that can be used to chain other operations. + public static IState ForEachData(this IState state, AsyncAction> action, out IDisposable disposable, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = -1) + { + disposable = AttachedProperty.GetOrCreate( + owner: state, + key: action, + state: (caller, line), + factory: static (s, a, d) => new StateForEach(s, a, $"ForEachData defined in {d.caller} at line {d.line}.")); + + return state; + } /// /// [DEPRECATED] Use .ForEachAsync instead