Home > Blockchain >  Rx.NET Is there an elegant way to create observable from callback which is passed in ctor
Rx.NET Is there an elegant way to create observable from callback which is passed in ctor

Time:07-03

I have this code

using System.Reactive.Linq;

var wrapper = new Wrapper<int>();

var clicker = new Clicker(wrapper.Action);

Observable
    .FromEvent
    (
        (Action<int> f) => wrapper.RegisterCallback(f),
        f => wrapper.UnregisterCallback(f)
    )
    .Subscribe(Console.WriteLine);

clicker.Click(7);
clicker.Click(2);
clicker.Click(5);

public class Clicker
{
    private readonly Action<int> _callback;

    public Clicker(Action<int> callback)
    {
        _callback = callback;
    }

    public void Click(int val)
    {
        _callback(val);
    }
}

public class Wrapper<T>
{
    private readonly List<Action<T>> _callbacks = new();

    public void RegisterCallback(Action<T> callback) => _callbacks.Add(callback);

    public void UnregisterCallback(Action<T> callback) => _callbacks.Remove(callback);

    public void Action(T val) => _callbacks.ForEach(f => f(val));
}

and I need to create an observable that reacts to Click call in Clicker. The callback is passed in ctor. Is there any other way of implementing that will not require implementing the Wrapper class.

CodePudding user response:

Your classes are trying to replicate basic functionality of delegates and observables... just use them as they are intended.

public class Clicker : ISubject<int>
{
    private readonly Subject<int> subject = new Subject<int>();

    public void Click(int val)
    {
        subject.OnNext(val);
    }

    public void OnCompleted() => subject.OnCompleted();
    public void one rror(Exception error) => subject.OnError(error);
    public void OnNext(int value) => subject.OnNext(value);
    public IDisposable Subscribe(IObserver<int> observer) => subject.Subscribe(observer);
    public IDisposable Subscribe(Action<int> onNext) => subject.Subscribe(onNext);
}
var clicker = new Clicker();
clicker.Subscribe(callback); // subscribe using the callback

clicker.Click(7);
clicker.Click(2);
clicker.Click(5);

clicker.OnNext(7); // equivalent
clicker.OnNext(2);
clicker.OnNext(5);

If you must insist on keeping the classes, create a subject in place of the clicker instance.

var subject = new Subject<int>();
var clicker = new Clicker(subject.OnNext);


subject.Subscribe(callback);
subject.OnNext(7);
clicker.Click(7); // equivalent
  • Related