[C#]Rxでsubscribeされた場所を探す


Rxで拡張メソッドを書いてた時に困ったことについて記載します。
あまり一般的な話ではないので誰得感がありますが…

例えば以下の拡張メソッドがあるとします。

static class Extensions
{
    public static IObservable<string> Filter(this IObservable<string> source, string v)
    {
        return source.Where(s => s == v);
    }
}

あんまり意味のない関数ですが単純に渡した文字列と等しい場合だけ後続に値を流すIObservableを作る関数です。
この関数を例えば以下のように使ってるとします。

static void Hogehoge(IObservable<string> source)
{
    source.Filter("test")
        .Subscribe(s => Console.WriteLine(s));
}

Filter関数を使ってIObservableを作った後にSubscribeしているだけです。

ここまでは特に問題がないのですがプログラムが巨大になっていく中でObservableに値を流しているはずなのに最終的な場所まで値がやってこないということが起こりました。

原因がよくわからず、仕方ないので値を流している部分からステップインで先に進んでいって途切れている場所を探すという手法をとることにしました。
そこでとても残念なことになりました。

このFilterを呼び出したのが誰なのかが全く分かりません。
スタックトレースも全く役に立ちません。

この状況で誰がFilterを呼び出したのか(=誰がSubscribe)しているのかをどうにかして探し出す必要がありました。
色々考えましたが最終的には以下のようにFilter関数を改造しました。

public static IObservable<string> Filter(this IObservable<string> source, string v)
{
    var st = Environment.StackTrace;
    return source.Where(s =>
    {
        Console.WriteLine(st);
        return s == v;
    });
}

Filterを実行したときのスタックトレースをキャプチャして表示することでどこから実行されたかが一目瞭然になりました。

最後に

もっといい方法があれば教えてください。