2012-04-27 7 views
3

私はRx初心者ですから、あなたが私に耐えられることを願っています。自分自身の練習として、そしておそらくは同僚のために示すことができるサンプルとして、Dns.BeginGetHostEntry()/ EndGetHostEntry()のDnsResolverとDnsResolverRxの2つのラッパークラスを実行しました。Rx Repeat()とReplay()を使用してDNSクエリをキャッシュして再起動する

クラスそれぞれが単一のpublic staticメソッドがあります。

void Resolve(string host, Action<IPHostEntry> getResult, Control context = null); 

を...といくつかの追加要件がそれを面白くするために: 1.コンテキストが提供されている場合、のgetResultは関連するスレッド に呼び出さなければなりません2.同じホストの以前の結果は、MaxResultAge秒間キャッシュされます。

非Rxバージョンは問題なく動作しますが、実際にはこの質問には関係ありません。 Rxのバージョンは次のようになります。

class DnsResolverRx 
{ 
    static Func<string, IObservable<IPHostEntry>> _resolver = Observable.FromAsyncPattern<string, IPHostEntry>(Dns.BeginGetHostEntry, Dns.EndGetHostEntry); 

    public static void Resolve(string host, Action<IPHostEntry> setResult, Control context = null) 
    { 
    IObservable<IPHostEntry> result; 
    result = _cache.GetOrCreateValue(// a trivial TryGetValue wrapper 
     host, 
    () => _resolver(host) 
     .Do(e => Debug.WriteLine("resolved")) 
     .Repeat() 
     .Do(e => Debug.WriteLine("repeated")) 
     .Replay(MaxResultAge) 
     .RefCount() 
    ); 

    result = result.Take(1); // each request needs only 1 result 

    if (context != null) 
     result = result.ObserveOn(context); 

    result.Subscribe(
     entry => setResult(entry), 
     ex => setResult(null) 
    ); 
    } 
} 

static void Main(string[] args) 
{ 
    for (int i=0; i<10; ++i) 
    { 
    int num = i; 
    Debug.WriteLine("start" + num); 
    DnsResolverRx.Resolve("chief", e => Debug.WriteLine("done"+num)); 
    Thread.Sleep(200); 
    } 

    Console.ReadLine(); 
} 

リプレイ()が動作しているようですので、MaxResultAge内の最初の要求は、すべて同じ結果を再利用し、完成されています。ただし、次の要求は)(リピートをトリガし、私は表面上は無限ループで終わる:

start0 
start1 
start2 
start3 
start4 
start5 
resolved 
repeated 
done0 
done1 
done2 
done3 
done4 
done5 
start6 
resolved 
repeated 
resolved 
repeated 
... and so on ad infinitum 

、誰もが何が起こっているかに私を啓発し、私が間違ってやっていることはできますか?

答えて

6

右揃えのFromAsyncPatternsは、本質的に再起動できない一回限りのものであり、購読時ではなく参照時に開始されるものです。

Observable.Defer(() => _resolver(host)) 

_resolver(host) 

の交換

は、トリックを行うようです。

オブジェクトが1つもない場合(そして私は他の問題を発見していません)、すぐにこの回答を受け入れます。

+1

それに釘付け。 'Retry'や' Repeat'を使うときに 'Defer'をしたいことがよくあります。 –

関連する問題