1

MainEngineObservable を Cold に変換するにはどうすればよいですか? この例から:

    public IObservable<int> MainEngine
    {
        get
        {
            Random rnd = new Random();
            int maxValue = rnd.Next(20);
            System.Diagnostics.Trace.TraceInformation("Max value is: " + maxValue.ToString());

            return (from sinlgeInt in Enumerable.Range(0, maxValue)
                    select sinlgeInt).ToObservable();
        }
    }

    public void Main()
    {
        // 1
        MainEngine.Subscribe(
                onNext: (item) => { System.Diagnostics.Trace.TraceInformation("Value is: " + item.ToString()); }
        );

        // 2
        MainEngine.Subscribe(
                onNext: (item) => { System.Diagnostics.Trace.TraceInformation("Gonna put it into XML: " + item.ToString()); }
        );
    }

質問 1: サブスクライバー 1 とサブスクライバー 2 で異なる結果が得られますが、両方が同じ結果を受け取るようにします。

質問 2: 2 番目のサブスクライバーを追加した時点から、両方のサブスクライバーが引き続き同じ結果を受け取ります。

4

2 に答える 2

4

最初の質問に関してはIObservable、ゲッターを2回呼び出すため、オブザーバーが同じものを購読していないという問題があります。

IObservableをローカル変数に割り当てると、問題が解決するようです。

IObservable<int> mainEngine = MainEngine;

mainEngine.Subscribe(onNext: (item) => { /* ... */ });
mainEngine.Subscribe(onNext: (item) => { /* ... */ });  

2 番目の質問について、サブスクリプションを単一の に共有したい場合は、次の方法IObservableを使用できます。Publish

IConnectableObservable<int> published = MainEngine.Publish();

published.Subscribe(onNext: (item) => { Console.WriteLine(item + " on observer 1"); });
published.Subscribe(onNext: (item) => { Console.WriteLine(item + " on observer 2"); });

published.Connect();

2 つのサブスクライバーはIObservable、インターリーブされた方法でからの結果を確認します。

0 on observer 1
0 on observer 2
1 on observer 1
1 on observer 2
etc.

サブスクライブの呼び出し後に新しいオブザーバーをサブスクライブすることもできます。その後、すべてのサブスクライバーに同じイベントが表示されます。新しいスレッドでオブザーバブルを実行し、遅延を導入することで、例を変更してこれをテストできます。

public static void Main()
{
    Random rnd = new Random();
    int maxValue = rnd.Next(20);

    /* Zip with Observable.Interval to introduce a delay */
    IObservable<int> mainEngine = Observable.Range(0, maxValue, Scheduler.NewThread)
        .Zip(Observable.Interval(TimeSpan.FromMilliseconds(100)), (a, b) => a);

    /* Publish the observable to share a subscription between observers */
    IConnectableObservable<int> published = mainEngine.Publish();

    /* Subscribe the first observer immediately, events are not yet being observed */
    published.Subscribe(onNext: (item) => { Console.WriteLine(item + " on observer 1"); });

    /* Start pushing events to the first observer */
    published.Connect();

    /* Wait one second and then subscribe the second observer */
    Thread.Sleep(1000);
    published.Subscribe(onNext: (item) => { Console.WriteLine(item + " on observer 2"); });

    Console.ReadKey();
}

最初のオブザーバーでのみ 1 秒間のイベントが表示され、その後、両方のオブザーバーが各イベントを同時に表示します。

于 2012-08-14T16:40:46.363 に答える
3

あなたのオブザーバブルはすでに冷たいです。オブザーバブルにサブスクライブするたびにオブザーバブルのインスタンスを取得すると、同じ値が得られます。

ホットであるように見える唯一の方法は、複数の呼び出しを行うと、異なる監視可能なインスタンスMainEngineが返されることです。しかし、それは彼らを本当に熱くするものではありません。

事実上、コールド オブザーバブル ファクトリが作成されました。

メソッドを本当にホットにするには、次のように呼び出しMainEngineを追加する必要があります。Defer

public IObservable<int> MainEngine
{
    get
    {
        return Observable.Defer(() =>
        {
            Random rnd = new Random();
            int maxValue = rnd.Next(20);

            System.Diagnostics.Trace.TraceInformation(
                "Max value is: " + maxValue.ToString());

            return Observable.Range(0, maxValue);
        });
    }
}

また、 への呼び出しを変更Enumerable.Rangeして削除したことにも注意してください。Observable.Range.ToObservable()

実際にホットにするためには、次のことを行う必要があります。

var hotObservable = MainEngine.Publish().RefCount();

これは事実上、複数のオブザーバブルが同時にサブスクライブされている場合、それらが基になるオブザーバブルを共有することを意味します。どれもサブスクライブされていない場合、基礎となるオブザーバブルはなくなり、新しいオブザーバーがサブスクライブしたときにのみ作成されます。

の実装はMainEngineデフォルトで を使用して実行Scheduler.Immediateされるため、オブザーバブルを別のスレッドで実行するように変更するまで、このコードの利点は見られないことに注意してください。

これが役立つことを願っています。

于 2012-08-15T01:55:04.477 に答える