Konrad Jamrozik
Konrad Jamrozik

Reputation: 3556

How to create an IObservable that emits on method call, without using Subjects or .NET events?

How to make this test pass without using the Subject class or .NET events?

[TestClass]
public class ObservableTests
{
    private readonly Subject<Unit> _subject = new Subject<Unit>();

    [TestMethod]
    public void ObservesMethodCall()
    {
        var eventCount = 0;
        IObservable<Unit> observable = _subject.AsObservable();
        observable.Subscribe(u => eventCount++);

        Assert.AreEqual(0, eventCount);
        Foo();
        Assert.AreEqual(1, eventCount);
    }

    private void Foo()
    {
        _subject.OnNext(Unit.Default);
    }
}

I want to avoid using subjects as they are not recommended. I don't want to use .NET events as RxNet supersedes them.

Related questions:

Firing an event every time a new method is called
It assumes we cannot modify the method being called.

How to create Observable that emits every time a member variable is updated (onCompleted never called)
Uses subjects.

Is there a way to create an observable sequence triggered by method calls without using Subject?
States Subjects are the way to go. However, I still want to learn how to do it without Subjects.

IObserver and IObservable in C# for Observer vs Delegates, Events
Shows how to solve the problem by implementing custom IObservable

Upvotes: 5

Views: 2472

Answers (2)

Shlomo
Shlomo

Reputation: 14350

In short, you want to procedurally trigger an observable, but without using subjects or events. You could use a custom delegate (@Enigmativity's answer), and you could also custom implement IObservable (basically re-inventing Subjects).

I'm going to contest the premise though: Use a subject. They aren't always recommended, but they suit your contrived problem as presented.

The bigger question you should be asking though is why you want to procedurally trigger an observable: The whole point of System.Reactive is that you can just worry about one side of a message: Either the receiver (observable) or sender (observer). You're trying to do both, which is what a Subject is. The problem with Subjects isn't some sort of implementation detail, or dogma (Subjects bad, Observables good), it's that the goal is to just focus on receiving messages, not sending and receiving.

Upvotes: 3

Enigmativity
Enigmativity

Reputation: 117064

This might be a bit like splitting hairs, but this works without the need of a subject:

[TestClass]
public class ObservaleTests
{
    private Action _action = null;

    [TestMethod]
    public void ObservesMethodCall()
    {
        var eventCount = 0;

        IObservable<Unit> observable =
            Observable.FromEvent(a => _action += a, a => _action -= a);

        observable.Subscribe(u => eventCount++);

        Assert.AreEqual(0, eventCount);
        Foo();
        Assert.AreEqual(1, eventCount);
    }

    private void Foo()
    {
        _action();
    }
}

Upvotes: 3

Related Questions