2017-01-15 4 views
1

外部ライブラリがイベントの代わりにコールバックを登録するだけの場合は、Observableを作成する最も良い方法は何ですか?コールバックをRx.Observableに変換するには?

イベントの場合はObservable.FromEventPatternを使用できますが、このケースでは私が持っている唯一のアイデアは、Subjectを使用し、各コールバックでイベントをキューに入れることです。

これを行うにはもっと良い方法はありますか?

+1

'Observable.Create'。彼によく知ってもらう。彼はRxのあなたの友人です。 'Observable.Create'と友達を作りながら' Subject 'との関係を断ち切ると、その関係からうまくいくことはありません;-) –

+0

あなたはいつも私に教えてくれると知っています:-)私は、コールバックを持つデリゲートオブジェクト全体をiOS APIに渡すと、Subjectは良い解決策でした。 – Thomas

+0

笑、私はしません。しかし、あなたが描写したシナリオでは、Obs.Createと被験者にとってひどい音に完璧に聞こえる! #dogmatic –

答えて

-1

イベントを発生させ、そのメソッドをコールバックとして渡すメソッドを作成します。

+0

それはSubjectを使うよりも清潔でしょうか? – Thomas

+0

私はなぜこの1つがdownvoted得たかわからない、そのidはサンプルを与えない以外に、上記の解決策は多かれ少なかれです – Thomas

+0

イベントは単なる言語統合コールバックです。このようにしてobservableに変換するには、外部ライブラリの周りに何らかの種類のプロキシークラスを持たなければなりません。それらのメソッドでは醜い 'FromEvent' /' FromEventPattern'メソッドを呼び出す必要があります。言い換えれば、それは正当な理由がないために二重の変換です。 – Shlomo

4

使用Observable.Create.はここに例を示します

void Main() 
{ 
    var target = new SampleCallbacker(); 
    var actionB = new Action<int>(i => Console.WriteLine($"{i} * {i} = {i * i}.")); 
    target.Register(actionB); 

    var observable = Observable.Create<int>(observer => 
    { 
     var action = new Action<int>(i => observer.OnNext(i)); 
     target.Register(action); 
     return() => target.Unregister(action); 
    }); 

    var subscription = observable.Subscribe(i => Console.WriteLine($"From observable: {i} was fired.")); 

    target.Fire(1); 
    target.Fire(2); 
    target.Fire(3); 
    Console.WriteLine("Unsusbscribing observable..."); 
    subscription.Dispose(); 
    target.Fire(4); 
    target.Fire(5); 
} 

class SampleCallbacker 
{ 
    private List<Action<int>> _actions = new List<System.Action<int>>(); 
    public void Register(Action<int> action) 
    { 
     _actions.Add(action); 
    } 

    public void Unregister(Action<int> action) 
    { 
     while (_actions.Remove(action)) 
     {} //loop remove 
    } 

    public void Fire(int i) 
    { 
     foreach (var action in _actions) 
     { 
      action(i); 
     } 
    } 
} 
+0

すてきな解決策。しかし、これはObservableの各サブスクライバのためにイベントを複数回購読するでしょうか? – Thomas

+0

はい。サブスクリプションを共有したい場合は、 'Create'コールの後に' .Publish()。RefCount() 'を追加してください。 – Shlomo

0

それは(例えば、クエリに対する応答を待っているために)単一のコールバックだ場合、あなたはStartAsyncメソッドを使用するにも使用することができます。現代のほとんどのAPIは、タスク/約束をサポートする可能性が高い。

Observable.StartAsync<string>(cancellation => 
    { 
     var source = new TaskCompletionSource<string>(); 
     yourlib.RegisterCallback(source.SetResult); 
     cancellation.Register(() => yourlib.UnregisterCallback(source.SetResult)); 
     return source.Task; 
    }); 

あなたが複数のサブスクリプションを避けたい場合は、いつでもこれ以上の加入者が存在しないときに処分されます単一subcriptionを共有するために.Publish().RefCount()を使用することができます。

+0

これは、コールバックが一度呼び出されると、オブジェクトのジョブが完了したので登録を解除する必要がないことを前提としています。 – Asti

関連する問題