我有一个方法void OnAction(Action<Person> callback)
,我想使用反应式扩展(Rx)从中创建一个IObservable<T>
。
我找到了两种可以帮助我的方法:Observable.FromEvent()
和Observable.Start()
:
var observable = Observable.Start(() =>
{
Person person = null;
_mngr.OnAction(p => person = p);
return person;
});
和
var observable = Observable.FromEvent<Person>(
action => _mngr.OnAction(action), //Add Handler
action => // Remove Handler
{
});
第一个有封闭,我必须评估if person != null
:
var foo= observable.Where(p =>
{
if(p!=null) //...
});
第二个采用Action参数,将给定的事件处理程序与基础.NET事件分离......但OnAction方法不是.NET事件。
两种方式都很好,但(在我看来)闻起来......
那么,从OnAction方法创建IObservable的最佳方法是什么?
答案 0 :(得分:2)
var personAsObservable
= Observable.Create<Person>(observer => {
_mngr.OnAction(person => {
observer.OnNext(person);
observer.OnCompleted();
});
});
如果您希望确保只调用此方法一次,则可以执行以下操作。
var publishedPerson = personaAsObservable.Replay(1);
publishedPerson.Connect();
publishedPerson.Subscribe(Console.WriteLine);
publishedPerson.Subscribe(Console.WriteLine);
publishedPerson.Subscribe(Console.WriteLine);
publishedPerson.Subscribe(Console.WriteLine);
答案 1 :(得分:2)
详细阐述克里斯的回答并提出你的意见。从这里开始:
var personAsObservable = Observable.Create<Person>(observer => {
_mngr.OnAction(person => {
observer.OnNext(person);
observer.OnCompleted();
});
return Disposable.Empty;
});
就目前而言,这将导致为每个订阅者调用OnAction
。
避免这种情况的一般方法是发布 observable。发布流会导致订阅者共享事件。
Publish
运算符返回可连接的observable 。这可以接受订阅者,但实际上不会订阅基础流,直到您调用Connect()
- 一个返回IDisposable
的方法,您可以使用该方法来控制与底层可观察对象的单一连接 - dispose它取消订阅。
有几个与发布相关的运算符可帮助您管理对基础流的订阅。
只要基础订阅正在运行, RefCount
就可以使用可连接的observable来管理连接并与订阅共享事件。完成后,后续订阅将重新启动。这可能足以满足您的需求。要使用它,请订阅以下内容(这是一种非常常见的Rx习语):
var personPub = personAsObservable.Publish().RefCount();
其他方法包括将Replay(n)
附加到源可观察源,其中n个事件将被缓存并重放到在基础流完成后到达的子序列订阅者。因此,如果您只想获得一次结果,这将非常有用。请注意,您必须明确地在Connect
上致电Replay
。您也可以致电Publish
并管理自己的连接。
请注意,附加这些运算符不会更改基础observable的行为 - 所有发布,缓存等都在附加的运算符上完成。因此,在上面的示例中,订阅者应该使用personPub
。
显式控制连接如下所示:
IConnectableObservable<Person> personPub = personAsObservable.Publish();
var subscriberOne = personPub.Subscribe(...); // personAsObservable not started
var connection = personPub.Connect(); // *now* personAsObservable is subscribed
var subscriberTwo = personPub.Subscribe(...); // shares underlying subscription
// but could miss events
connection.Dispose(); // underlying connection terminated
// but may have already OnCompleted anyway
// in which case this is a no-op