Changing observable source during the same subscription - c#

How can I change a Observable source while keeping the subscription intact? Yea, this is easy to accomplish with a Subject but best practises says not to use a subject.
Here an example:
Worker.cs
public class Worker
{
public IObservable<Worker> IsWorking {get;}
public string Name {get;}
public Worker(string name)
{
Name = name;
IsWorking = Observable.Interval(TimeSpan.FromSeconds(1))
.Select(_ => this);
}
}
This class exposes an Observable which fires every second.
WorkerState.cs
public class WorkerState
{
public Worker CurrentWorker
{
set => WorkerIsBusy = value.IsWorking;
}
public IObservable<Worker> WorkerIsBusy { get; private set; }
}
This class is supposed to hold a worker unit, which can be changed on the fly but the Subscription should be automatically attached to the current worker. (This is would be the place for a Subject)
And here the test:
Program.cs
public class Program
{
public async Task Run()
{
var state = new WorkerState();
state.CurrentWorker = new Worker("A");
state.WorkerIsBusy.Subscribe(worker =>
Console.WriteLine($"Worker {worker.Name}"));
await Task.Delay(3000);
Console.WriteLine("Should change now to B...");
state.CurrentWorker = new Worker("B");
Console.Read();
}
}
But my ouput is the following:
Worker A
Worker A
Should change now to B...
Worker A
Worker A
Worker A
...
instead of switching to worker B.

The approach you should almost always use for re-subscribing is to get the query to resubscribe for you by using the .Switch() operator.
Something like this:
var switcher = new Subject<IObservable<int>>();
var subscription = switcher.Switch().Subscribe(x => Console.WriteLine(x));
switcher.OnNext(Observable.Return(42));
switcher.OnNext(Observable.Range(0, 3));
That produces:
42
0
1
2
No re-subscription required.
For your code you need to change WorkerState to this:
public class WorkerState
{
private Worker currentWorker = null;
private Subject<Worker> currentWorkerSubject = new Subject<Worker>();
public Worker CurrentWorker
{
set
{
currentWorker = value;
currentWorkerSubject.OnNext(value);
}
}
public IObservable<Worker> WorkerIsBusy
{
get =>
currentWorkerSubject
.StartWith(currentWorker)
.Where(w => w != null)
.Select(w => w.IsWorking)
.Switch();
}
}
Then your code works (with the minor caveat that the await Task.Delay(3000); has a small race condition with the Observable.Interval(TimeSpan.FromSeconds(1)) inside Worker. Change the await to 3500 to avoid it.

The issue that you have is that you've subscribed to the previous value of WorkerIsBusy, and although you've changed the reference, you haven't changed the subscription, which still points at the previous value.
You would need to intercept (actually subscribe to) the worker.IsWorking in your WorkerState class, and unsubscribe / resubscribe when the property value changes.
Or you could use a Subject - I don't understand why you wouldn't?

Related

How to test object that pushes values to using Reactive Extensions via `Sample` method

I have a class called ValuePusher with a property named Value and receives a dependency of type ValueReceiver, also with a property named Value. The former class arranges to 'push' values to an instance of the latter class via a System.Reactive.Subjects.Subject<int> object. Initially it pushes values one for one, but later it will restrict the amount of values pushed using the Sample method - note the commented-out call to this method in the code below:
public sealed class ValuePusher : IDisposable
{
private readonly ValueReceiver _receiver;
private readonly IScheduler _scheduler;
private readonly Subject<int> _subject;
private int _value;
public ValuePusher(ValueReceiver receiver, IScheduler scheduler)
{
_receiver = receiver;
_scheduler = scheduler;
// Arrange to push values to `receiver` dependency
_subject = new Subject<int>();
_subject.ObserveOn(_scheduler)
//.Sample(TimeSpan.FromMilliseconds(50), _scheduler)
.SubscribeOn(_scheduler)
.Subscribe(i => PushCurrentValueToReceiver());
}
public int Value
{
get => _value;
set
{
_value = value;
_subject.OnNext(0);
}
}
private void PushCurrentValueToReceiver()
{
_receiver.Value = Value;
}
public void Dispose()
{
_subject?.OnCompleted();
_subject?.Dispose();
}
}
public class ValueReceiver
{
public int Value { get; set; }
}
I write a unit test for the code above, involving a Microsoft.Reactive.Testing.TestScheduler, which passes:
[TestMethod]
[Timeout(1000)]
public void ReceiverReceivesValueFromPusherViaScheduler()
{
var scheduler = new TestScheduler();
var receiver = new ValueReceiver();
using (var pusher = new ValuePusher(receiver, scheduler))
{
scheduler.Start();
pusher.Value = 1;
scheduler.AdvanceBy(1);
Assert.AreEqual(1, receiver.Value);
}
}
However, if uncomment the call to Sample method the test fails to complete and times-out. How can I change the test code or the production code to verify that values are pushed to the receiving object when Sample is in use?
Source code: https://github.com/DanStevens/StackOverflow71409012
The reason why it times out, seems to be the combination of .Sample(...) and scheduler.Start().
scheduler.Start() tries execute everything that has been scheduled, but I think Sample() keeps scheduling a sample, and thus scheduler.Start() never finishes.
So if you remove scheduler.Start(), and do this instead:
...
// Following line instead of scheduler.Start(), needed because of the .SubscribeOn(...) call
scheduler.AdvanceBy(1);
pusher.Value = 1;
scheduler.AdvanceBy(TimeSpan.FromMilliseconds(50).Ticks);
Assert.AreEqual(1, receiver.Value);
...
it should work with or without the call to .Sample(...).
[Edit] as per Dan Stevens' comment.

Observable class property doesn't trigger subscription

Simple observable variable works as expected an triggers callback immediately on the same thread.
Why a class variable of any observable type (Subject, ISubject, Observable, IObservable) doesn't trigger callback?
Example with simple variable - [Works]
var x1 = new Subject<string>();
var x2 = x1.DistinctUntilChanged();
x2.Subscribe(o =>
{
// Triggered as expected
});
x1.OnNext("Hello");
Example with a class - [Does NOT work]
public class InstrumentModel
{
public Subject<string> Demo => new Subject<string>();
}
var class1 = new InstrumentModel();
class1.Demo
//.DistinctUntilChanged()
//.SubscribeOn(Scheduler.CurrentThread)
//.ObserveOn(Scheduler.CurrentThread)
.Subscribe(o =>
{
// Never triggered
});
class1.Demo.OnNext("Hello");
Problem is that you made Demo to return new instance of Subject<string> every time it is used.
Demo instance that you subscribed too, is not the same instance you called OnNext() on.
class1.Demo.Subscribe(...); // makes new instance `Subject<string>`
class1.Demo.OnNext("Hello"); // makes another new instance of `Subject<string>`
Keep it the same instance and it will work. For example:
public class InstrumentModel
{
public Subject<string> Demo = new Subject<string>();
}
or:
public class InstrumentModel
{
public InstrumentModel()
{
this.Demo = new Subject<string>();
}
public Subject<string> Demo { get; }
}

Run background Task until object falls out of scope

I want to implement a class which runs a background task, looping and updating the state of the class. Once the class falls out of scope, running the background task has no value, so I would like to exit the loop and allow the task to complete and release the thread.
public class ValueProvider
{
private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
public string Value {get; private set;}
public IChangeToken ChangeToken => _reloadToken;
public void Load()
{
// Load the initial value.
Value = "Foo";
// Watch for changes to and reload the value.
WatchForChanges();
}
private void WatchForChanges() => Task.Run(WatchAsync);
private async Task WatchAsync()
{
var stillInScope = true;
while(stillInScope)
{
// Watch for new values.
Value = await LoadNewValueAsync();
// Signal a change.
OnReload();
}
}
private async Task<string> LoadNewValueAsync()
{
// Simulate an actual lookup which blocks until a new value is available.
await Task.Delay(TimeSpan.FromSeconds(30));
return "Bar";
}
private void OnReload()
{
var previousToken = Interlocked.Exchange(
ref _reloadToken,
new ConfigurationReloadToken());
previousToken.OnReload();
}
}
Since the created Task has a reference to the ValueProvider, the instance will never fall out of scope. The solution probably has to include accessing the ValueProvider from the background task via a WeakReference<T> to allow it to go out of scope, but I'm open to solutions.
How can I detect that the "foreground" object has fallen out of scope and stop the accompanied background task?

Constructor that takes any delegate as a parameter

Here's the simplified case. I have a class that stores a delegate that it will call on completion:
public class Animation
{
public delegate void AnimationEnd();
public event AnimationEnd OnEnd;
}
I have another utility class that I want to subscribe to various delegates. On construction I want itself to register to the delegate, but other than that it doesn't care about the type. The thing is, I don't know how to express that in the type system. Here's my pseudo-C#
public class WaitForDelegate
{
public delegateFired = false;
// How to express the generic type here?
public WaitForDelegate<F that's a delegate>(F trigger)
{
trigger += () => { delegateFired = true; };
}
}
Thanks in advance!
Thanks to Alberto Monteiro, I just use System.Action as the type for the event. My question now is, how to pass the event to the constructor so it can register itself? This might be a very dumb question.
public class Example
{
Animation animation; // assume initialized
public void example()
{
// Here I can't pass the delegate, and get an error like
// "The event can only appear on the left hand side of += or -="
WaitForDelegate waiter = new WaitForDelegate(animation.OnEnd);
}
}
I'm afraid you can't do what you're asking.
First up, you can't constrain by delegates. The closest code to legal C# is this:
public class WaitForDelegate<F> where F : System.Delegate
{
public bool delegateFired = false;
public WaitForDelegate(F trigger)
{
trigger += () => { delegateFired = true; };
}
}
But it won't compile.
But the bigger problem is that you can't pass delegates around like this anyway.
Consider this simplified class:
public class WaitForDelegate
{
public WaitForDelegate(Action trigger)
{
trigger += () => { Console.WriteLine("trigger"); };
}
}
I then try to use it like this:
Action bar = () => Console.WriteLine("bar");
var wfd = new WaitForDelegate(bar);
bar();
The only output from this is:
bar
The word trigger doesn't appear. This is because delegates are copied by value so that the line trigger += () => { Console.WriteLine("trigger"); }; is only attaching the handler to trigger and not bar at all.
The way that you can make all of this work is to stop using events and use Microsoft's Reactive Extensions (NuGet "Rx-Main") which allows you to turn events into LINQ-based IObservable<T> instances that can get passed around.
Here's how my example code above would then work:
public class WaitForDelegate
{
public WaitForDelegate(IObservable<Unit> trigger)
{
trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
}
}
And you now call it like:
Action bar = () => Console.WriteLine("bar");
var wfd = new WaitForDelegate(Observable.FromEvent(h => bar += h, h => bar -= h));
bar();
This now produces the output:
bar
trigger
Notice that the Observable.FromEvent call contains the code to attach and detach the handler in a scope that has access to do so. It allows the final subscription call to be unattached with a call to .Dispose().
I've made this class quite simple, but a more complete version would be this:
public class WaitForDelegate : IDisposable
{
private IDisposable _subscription;
public WaitForDelegate(IObservable<Unit> trigger)
{
_subscription = trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
}
public void Dispose()
{
_subscription.Dispose();
}
}
An alternative if you don't want to go for the full use of Rx is to do this:
public class WaitForDelegate : IDisposable
{
private Action _detach;
public WaitForDelegate(Action<Action> add, Action<Action> remove)
{
Action handler = () => Console.WriteLine("trigger");
_detach = () => remove(handler);
add(handler);
}
public void Dispose()
{
if (_detach != null)
{
_detach();
_detach = null;
}
}
}
You call it like this:
Action bar = () => Console.WriteLine("bar");
var wfd = new WaitForDelegate(h => bar += h, h => bar -= h);
bar();
That still does the correct output.
In .NET there is already a delegate that doesn't receive no parameters, it is the Action
So you Animation class could be like that:
public class Animation
{
public event Action OnEnd;
}
But you can pass events as parameters, if you try that you will receive this compilation error
The event can only appear on the left hand side of += or -="
So lets create a interface, and declare the event there
public interface IAnimation
{
event Action OnEnd;
}
Using the interface approach you have no external dependencies and you can have many classes that implements that, also is a good practice, depends of abstractions instead concrete types. There is acronym called SOLID that explain 5 principles about better OO code.
And then your animation class implements that
Obs.: The CallEnd method is just for test purpose
public class Animation : IAnimation
{
public event Action OnEnd;
public void CallEnd()
{
OnEnd();
}
}
And now you WaitForDelegate will receive a IAnimation, so the class can handle any class that implements the IAnimation class
public class WaitForDelegate<T> where T : IAnimation
{
public WaitForDelegate(T animation)
{
animation.OnEnd += () => { Console.WriteLine("trigger"); };
}
}
Then we can test the code that we did with the following code
public static void Main(string[] args)
{
var a = new Animation();
var waitForDelegate = new WaitForDelegate<IAnimation>(a);
a.CallEnd();
}
The result is
trigger
Here is the working version on dotnetfiddle
https://dotnetfiddle.net/1mejBL
Important tip
If you are working with multithread, you must take some caution to avoid Null Reference Exception
Let's look again the CallEnd method that I've added for test
public void CallEnd()
{
OnEnd();
}
OnEnd event could have not value, and then if you try to call it, you will receive Null Reference Exception.
So if you are using C# 5 or lower, do something like this
public void CallEnd()
{
var #event = OnEnd;
if (#event != null)
#event();
}
With C# 6 it could be like that
public void CallEnd()
=> OnEnd?.Invoke();
More explanation, you could have this code
public void CallEnd()
{
if (OnEnd != null)
OnEnd();
}
This code that is above, probably make you think that you are safe from Null Reference Exception, but with multithread solution, you aren't. That's because the OnEnd event could be set to null between the execution of if (OnEnd != null) and OnEnd();
There is a nice article by Jon Skeet about it, you cann see Clean event handler invocation with C# 6

How to implement an event using Reactive Extensions

The Reactive Extensions allow you to easily subscribe to an event using Observable.FromEventPattern, but I can't find anything on how you might implement an event when you have an IObservable.
My situation is this: I need to implement an interface which contains an event. That event is supposed to be called whenever a certain value of my object changes, and for thread safety reasons I need to call this event on a certain SynchronizationContext. I am also supposed to call each event handler with the current value on registration.
public interface IFooWatcher
{
event FooChangedHandler FooChanged;
}
Getting an observable that does what I want is rather easy with Rx using BehaviorSubject:
public class FooWatcher
{
private readonly BehaviorSubject<Foo> m_subject;
private readonly IObservable<Foo> m_observable;
public FooWatcher(SynchronizationContext synchronizationContext, Foo initialValue)
{
m_subject = new BehaviorSubject<Foo>(initialValue);
m_observable = m_subject
.DistinctUntilChanged()
.ObserveOn(synchronizationContext);
}
public event FooChangedHandler FooChanged
{
add { /* ??? */ }
remove { /* ??? */ }
}
}
Now I am looking for an easy way to have the add and remove functions subscribe and unsubscribe the passed FooChangedHandler as an Observer<Foo> on m_observable. My current implementation looks similar to this:
add
{
lock (m_lock)
{
IDisposable disp = m_observable.Subscribe(value);
m_registeredObservers.Add(
new KeyValuePair<FooChangedHandler, IDisposable>(
value, disp));
}
}
remove
{
lock (m_lock)
{
KeyValuePair<FooChangedHandler, IDisposable> observerDisposable =
m_registeredObservers
.First(pair => object.Equals(pair.Key, value));
m_registeredObservers.Remove(observerDisposable);
observerDisposable.Value.Dispose();
}
}
However, I hope to find an easier solution, because I need to implement several of these events (of differing handler types). I tried to roll my own generic solution but it creates some additional problems that need to be worked around (in particular, how you generically work with a delegate that takes a parameter of T), so I would prefer to find an existing solution that bridges the gap in this direction - just as FromEventPattern does the reverse.
You could do this:
public event FooChangedHandler FooChanged
{
add { m_observable.ToEvent().OnNext += value; }
remove { m_observable.ToEvent().OnNext -= value; }
}
However, on the remove, I think perhaps you just may want to dispose of the subscription ... or perhaps get the Action from ToEvent() and store that as a member. Untested.
EDIT: You'll have to use Action instead of a FooChangedHandler delegate, however.
EDIT 2: Here's a tested version. I suppose you need to use FooChangedHandler, however, since you have a bunch of these pre-existing handlers?
void Main()
{
IObservable<Foo> foos = new [] { new Foo { X = 1 }, new Foo { X = 2 } }.ToObservable();
var watcher = new FooWatcher(SynchronizationContext.Current, new Foo { X = 12 });
watcher.FooChanged += o => o.X.Dump();
foos.Subscribe(watcher.Subject.OnNext);
}
// Define other methods and classes here
//public delegate void FooChangedHandler(Foo foo);
public interface IFooWatcher
{
event Action<Foo> FooChanged;
}
public class Foo {
public int X { get; set; }
}
public class FooWatcher
{
private readonly BehaviorSubject<Foo> m_subject;
public BehaviorSubject<Foo> Subject { get { return m_subject; } }
private readonly IObservable<Foo> m_observable;
public FooWatcher(SynchronizationContext synchronizationContext, Foo initialValue)
{
m_subject = new BehaviorSubject<Foo>(initialValue);
m_observable = m_subject
.DistinctUntilChanged();
}
public event Action<Foo> FooChanged
{
add { m_observable.ToEvent().OnNext += value; }
remove { m_observable.ToEvent().OnNext -= value; }
}
}
Given that you are already mixing the boundaries between reactive and more normal code, you could do a less reactive version. To start simply declare a normal event pattern
public event FooChangedHandler FooChanged;
protected void OnFooChanged(Foo)
{
var temp = FooChanged;
if (temp != null)
{
temp(new FooChangedEventArgs(Foo));
}
}
and then simply connect the observable to it in the constructor
m_Observable.Subscribe(foo => OnFooChanged(foo));
It's not very Rx but it is incredibly simple.

Categories