我有Action<Action> operation
执行一些长时间运行的工作,并通过提供的Action
参数发送心跳。
在我调用它之前,我想设置一个IObservable<Unit>
,每次操作发送心跳时都会生成一个Next元素。
我该怎么做?
创建IObservable
是not that complicated,但我猜测概念上最简单的方法是create it from an event,但遗憾的是你不能在方法体中创建一个事件(除非你知道一个办法)。我可以使用Observable.FromEvent(Action<Action> addHandler, Action<Action> removeHandler)
,但这需要丑陋的封闭式操作来转发方法调用(参见下面的示例)。
有更优雅的方式吗?
Action forward = null;
Action sendHeartbeat = () => { if (forward != null) forward(); };
//ugly, since it does not scale to multiple observers:
IObservable<Unit> heartbeatObs =
Observable.FromEvent(handler => {
forward = handler;
}, _ => { forward = null; });
operation(sendHeartbeat);
即使我没有使用零维向前动作,也不使用它的集合,这将是丑陋的,因为我将为+=
全部实现-=
和EventHandlers
运算符试。
答案 0 :(得分:1)
我不确定我是否完全理解你的问题,但如果我有,你可以做这样的事情,它使用Subject
传输心跳。您可以在命名空间System.Reactive.Subjects
中找到主题。
// set up a subject
Subject<Unit> heartbeatSubject=new Subject<Unit>();
// set up the heartbeataction to push units down the subject
Action sendHeartbeat = () => { heartbeatSubject.OnNext(Unit.Default); };
// use the heartbeat subject somehow.
heartbeatSubject.Subscribe(_=>Console.WriteLine("Operation produced a heartbeat"));
// start the operation
operation(sendHeartbeat);
修改强>
正如您的评论所述,根据官方的RX系列,除了演示/示例代码外,最好避免使用主题。我刚刚使用了Observable.Create,这可能会更好吗?
Action<Action> longRunningAction=(
hb => { for(int i=0;i<100;i++) { hb(); Thread.Sleep(1000);}});
var ob=Observable.Create<Unit>(
(IObserver<Unit> observer) =>
{
longRunningAction(()=>observer.OnNext(Unit.Default));
return Disposable.Create(() => Console.WriteLine("Observer has unsubscribed"));
});
ob.Subscribe(_=>Console.WriteLine("Received a heartbeat"));