3

Subject<T>ReplaySubject<T>およびその他の機能の仕組みを理解しようとしています。次に例を示します。

(サブジェクトは観察可能観察者です)

public IObservable<int> CreateObservable()
{
     Subject<int> subj = new Subject<int>();                // case 1
     ReplaySubject<int> subj = new ReplaySubject<int>();    // case 2

     Random rnd = new Random();
     int maxValue = rnd.Next(20);
     Trace.TraceInformation("Max value is: " + maxValue.ToString());

     subj.OnNext(-1);           // specific value

     for(int iCounter = 0; iCounter < maxValue; iCounter++)
     {
          Trace.TraceInformation("Value: " + iCounter.ToString() + " is about to publish");
          subj.OnNext(iCounter);
      }

      Trace.TraceInformation("Publish complete");
      subj.OnComplete();

      return subj;
 }

 public void Main()
 {
     //
     // First subscription
     CreateObservable()
         .Subscribe(
               onNext: (x)=>{  
                  Trace.TraceInformation("X is: " + x.ToString()); 
      });

     //
     // Second subscribe
     CreateObservable()
         .Subscribe(
               onNext: (x2)=>{  
                  Trace.TraceInformation("X2 is: " + x.ToString());
     });

ケース 1: 奇妙な状況はSubject<T>、サブスクリプションが作成されていない場合 (???) - 「X is:」というテキストがまったく表示されない - 「Value is:」と「Max value is」のみが表示される...Subject<T>がサブスクリプションに値をプッシュしないのはなぜですか?

ケース 2: 使用する場合- サブスクリプションに値が表示されますが、オプションを何にもReplaySubject<T>適用できませんでした。DeferオブザーバブルではありませSubjectん....CreateObservable関数はコールドオブザーバブルであるため、すべてのサブスクリプションは異なる値を受け取ります。はどこDeferですか?

4

2 に答える 2

10

何もないところからオブザーバブルを作成する必要があるときはいつでも、 Observable.Create を最初に考える必要があります。被験者は次の 2 つの場合に写真に入ります。

  • すべてのサブスクライバーがデータを受信できるようにするには、データをフィードするための何らかの「アドレス指定可能なエンドポイント」が必要です。これを、呼び出し側 (デリゲート呼び出しによる) とサブスクリプション側 (+- および -= 構文を組み合わせたデリゲートによる) の両方を持つ .NET イベントと比較してください。多くの場合、Observable.Create を使用して同じ効果を得ることができます。

  • クエリ パイプラインでメッセージをマルチキャストし、複数のサブスクリプションをトリガーすることなく、クエリ ロジックの多くのフォークによって観察可能なシーケンスを効果的に共有する必要があります。(寮でお気に入りの雑誌を一度購読し、コピー機をレター ボックスのすぐ後ろに置くことを考えてみてください。購読料は 1 回払いますが、OnNext を通じて配信された雑誌は、すべての友人がレター ボックスで読むことができます。)

また、多くの場合、必要なことを正確に実行する組み込みのプリミティブが Rx に既に存在します。たとえば、既存の概念 (イベント、タスク、非同期メソッド、列挙可能なシーケンスなど) と橋渡しする From* ファクトリ メソッドがあり、その中には隠れたサブジェクトを使用しているものもあります。マルチキャスト ロジックの 2 番目のケースでは、Publish、Replay などの演算子ファミリがあります。

于 2012-08-21T07:18:23.280 に答える
4

コードが実行されるタイミングに注意する必要があります。

「ケース 1」では、 a を使用すると、 &のすべての呼び出しが、メソッドによってオブザーバブルが返される前に終了するSubject<T>ことに気付くでしょう。を使用しているため、これは、後続のサブスクリプションですべての値が失われることを意味するため、取得したものを取得することを期待する必要があります-何も取得しません。OnNextOnCompletedCreateObservableSubject<T>

オブザーバーがサブスクライブするまで、サブジェクトの操作を遅らせる必要があります。Createメソッドを使用してそれを行うには。方法は次のとおりです。

public IObservable<int> CreateObservable()
{
    return Observable.Create<int>(o =>
    {
        var subj = new Subject<int>();
        var disposable = subj.Subscribe(o);

        var rnd = new Random();
        var maxValue = rnd.Next(20);
        subj.OnNext(-1);
        for(int iCounter = 0; iCounter < maxValue; iCounter++)
        {
            subj.OnNext(iCounter);
        }
        subj.OnCompleted();

        return disposable;
    });
}

簡潔にするために、すべてのトレース コードを削除しました。

したがって、すべてのサブスクライバーに対して、メソッド内のコードの新しい実行をCreate取得し、 internal から値を取得するようになりましたSubject<T>

メソッドの使用は、Create通常、メソッドから返されるオブザーバブルを作成する正しい方法です。

または、 a を使用して、メソッドReplaySubject<T>の使用を避けることもできます。Createただし、これは多くの理由で魅力的ではありません。作成時にシーケンス全体の計算を強制します。これにより、リプレイ サブジェクトを使用しなくてもより効率的に生成できるコールド オブザーバブルが得られます。

さて、余談ですが、件名を使用しないようにしてください。一般的なルールは、サブジェクトを使用している場合、何か間違ったことをしているということです。このCreateObservable方法は、次のように記述したほうがよいでしょう。

public IObservable<int> CreateObservable()
{
    return Observable.Create<int>(o =>
    {
        var rnd = new Random();
        var maxValue = rnd.Next(20);
        return Observable.Range(-1, maxValue + 1).Subscribe(o);
    });
}

主語は全く必要ありません。

これが役立つかどうか教えてください。

于 2012-08-20T08:22:52.720 に答える