12

Reactive Extensions などについて msdn を読んでいると、IObservable を実装するべきではなく、Observable.Create を使用するべきであるという推奨事項が見つかりました...これを読むまでに、私のプロジェクトには既にObservableImplementation<T>クラスがありました。イベントを Observables に変換したいところならどこでも、IObservable ソースとして使用されます。

System.Reactiveの実装を読みましたがAbstractObservable<T>、彼らのコードと私のコードの間に大きな違いは見つかりませんでした。では、IObservable を実装することの何が問題なのですか? 独自のプロパティを追加できます...

充実のために、ここに私の実装があります。私が何か間違ったことをしたかどうか教えてください!

public sealed class ObservableImplementation<T> : IObservable<T>
{
    class Subscription : IDisposable
    {
        private readonly Action _onDispose;
        public Subscription(Action onDispose)
        {
            _onDispose = onDispose;
        }

        public void Dispose()
        {
            _onDispose();
        }
    }


    public void Raise(T value)
    {
        _observers.ForEach(o => o.OnNext(value));
    }
    public void Completion()
    {
        _observers.ForEach(o => o.OnCompleted());
        _observers.Clear();
    }

    private readonly List<IObserver<T>> _observers = new List<IObserver<T>>();  
    public IDisposable Subscribe(IObserver<T> observer)
    {
        var subscription = new Subscription(() => _observers.Remove(observer));
        _observers.Add(observer);
        return subscription;
    }
    public bool AnyObserverPresent { get { return _observers.Any(); } }
}
4

3 に答える 3

22

IObservable<T> を直接実装することをお勧めしない理由はいくつかあります。

1 つは、オブザーバー文法の違反に対する保護の欠如です。たとえば、シーケンスは OnCompleted 呼び出しに続く OnNext 呼び出しの動作を示すことがありますが、これは無効です。Observable.Create<T> メソッドと ObservableBase<T> 基本型は、端末メッセージの受信時にオブザーバーを自動的にデタッチすることで、これを処理します。したがって、コードが間違ったことを行ったとしても、オブザーバーは不正なシーケンスを認識していません。

ところで、これは C# の反復子に似ています。IEnumerable<T> を手動で実装すると、列挙子の MoveNext が false (OnCompleted に類似) を返したときに、後続の呼び出しが気が変わって true を返し始める (OnNext に類似) ようにする必要があります。

MoveNext がコレクションの末尾を通過した場合、列挙子はコレクションの最後の要素の後に配置され、MoveNext は false を返します。列挙子がこの位置にある場合、Reset が呼び出されるまで、MoveNext への後続の呼び出しも false を返します。(出典: MSDN)

C# 2.0 または VB 11.0 で反復子を使用する場合、このような問題は解決されます。これは、Observable.Create<T> メソッドと ObservableBase<T> 基本型に似ています。

上記の議論に関連する理由は、クリーンアップです。サブスクリプションの Dispose 呼び出しから戻ると、オブザーバーにはメッセージが表示されなくなりますか? ターミナル メッセージをオブザーバーに送信すると、関連するサブスクリプションの Dispose ロジックが自動的に呼び出されますか? どちらも正しく理解するのは簡単ではないため、基本的な実装がそれを処理します。

もう 1 つの理由は、CurrentThreadScheduler に関係しており、そのスケジューラーでの実行時に Subscribe 呼び出しを非同期にできるようにします。基本的に、Subscribe の呼び出し中に現在のスレッドにトランポリンをインストールする必要があるかどうかを確認する必要があります。私たちは、誰もがこのことを知って正しいことをするとは思っていません。

あなたの特定のケースでは、ここで他の人が気づいたように、ほとんどサブジェクトを構築しています。サブジェクトの 1 つだけを使用するか、独自のタイプで包含してラップします (たとえば、送信側の "オブザーバー" 側を、受信側の "オブザーバブル" 側ではなく他のパーティからアクセスできるようにする場合)。

于 2012-05-23T23:19:01.413 に答える
10

実装すべきでないIObservable<T>理由は、通常は実装しない理由と同じIEnumerable<T>です。おそらく、誰かがあなたが望むものをすでに構築しているからです。この場合、基本的Subject<T>にほとんどの部分を再実装しました。

編集:コメントの怠惰な質問に関しては、私はそれをこのように実装します:

var lazyObservable = Observable.Create<TFoo>(subj => { /*TODO: Implement Me to load from reflection*/ })
    .Multicast(new Subject<TFoo>())   // This means it'll only calc once
    .RefCount();    // This means it won't get created until someone Subscribes
于 2012-05-07T17:45:53.190 に答える