I need to monitor for changes of nullable Foo, including Foo = null or changes of any property like Foo.Bar = 123.
So I am using this syntax (similar to recommended):
WhenAnyValue(o => o.Foo, o => o.Foo!.Bar, (foo, bar) => (foo, bar))
to subscribe to changes of both Foo and Bar of my view model:
public class VM : ReactiveObject
{
[Reactive]
public Foo? Foo { get; set; }
}
public class Foo : ReactiveObject
{
[Reactive]
public int Bar { get; set; }
}
However, this will run subscriber multiple time with stale values. After Foo = null subscriber is called with previous value of Bar and after Foo = new() subscriber is called twice: with previous value of Bar and with correct one. This can be demonstrated with following code:
var vm = new VM() { Foo = new Foo { Bar = 1 } };
vm.WhenAnyValue(o => o.Foo, o => o.Foo!.Bar, (foo, bar) => (foo, bar))
.Subscribe(o => Console.WriteLine($"{o.foo?.GetHashCode()} {o.bar}"));
vm.Foo = null; // #1
vm.Foo = new Foo { Bar = 2 }; // #2
The output looks like this:
58225482 1
1 << stale Bar
32347029 1 << stale Bar
32347029 2 << extra call
Instead I want something like this:
58225482 1
0
32347029 2
In other words, I don't want to have stale values and extra subscriber call if possible.
The Foo == null check inside subscriber will solve #1. But maybe there is a different rx solution to such a problem? Or is moving null check outside of subscriber somehow is also ok?
As for #2, I have only idea of workaround with storing previous value of Foo and ignore first call if previous value was null. Again, it's a procedural way of programming. How this should be done in rx world of programming?
To demonstrate the problem more clearly I have increased the number
Fooproperties:Then the output of
will contain lots of stale states:
Here is a fixed version of subscriber:
Now the output is as expected, one line per change:
In other words:
null propagated values should not be used inside subscriber, their purpose is to detect their individual changes, e.g. whenvm.Foo.Bar = 123;EDIT: The second statement is incorrect, with discard there is no stale state anymore and values are correct, unless subscriber takes too long to finish, but that's another story.