5

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

Konrad Jamrozik
  • 3,254
  • 5
  • 29
  • 59

2 Answers2

3

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();
    }
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
3

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.

Shlomo
  • 14,102
  • 3
  • 28
  • 43
  • The problem is not contrived. This is one of the most plain, common of use cases: "I want to observe method calls, how do I do it?". More concretely, I am writing a class that triggers something and I want to expose such trigger occurrences as IObservable in this class interface. – Konrad Jamrozik Sep 25 '17 at 03:57
  • 2
    The problem as presented is contrived: You essentially want a subject, without using `Subject`. I suggest you read some of the linked answers as to *why* a `Subject` is not recommended. You'll notice that it's really the designs that tend to form around `Subject` that aren't recommended, not the class itself. – Shlomo Sep 25 '17 at 15:22
  • There is too big jump for me from "I want to expose method calls as IObservable" to "you essentially want a Subject, thus your problem is contrived". Dave Sexton's "To Use Subject Or Not To Use Subject?" article seems to say that indeed Subjects are the right approach for this scenario, but the explanation is far from trivial. – Konrad Jamrozik Sep 28 '17 at 05:33