如何正确观察非标准事件?

时间:2015-08-08 17:52:19

标签: c# system.reactive

我是Reactive Extensions的新手,并处理具有如下定义事件的COM库:

public delegate void MyDelegate(int requestId, double price, int amount);
public event MyDelegate MyEvent;

我该如何正确观察这个?我尝试使用Observable.FromEvent(),但由于事件的参数不属于EventArgs类型,因此我不知道FromEvent()FromEventPattern()将如何运作。

我目前的解决方法是将自定义委托附加到事件然后调用Subject.OnNext(),但我猜这不是我应该怎么做。

以下是我当前解决方法的一个示例:

        MyEvent += new MyDelegate((int requestId, double price, int amount) =>
        {
            Task.Run(() =>
            {
                var args = new MyArgs()
                {
                    requestId = requestId,
                    price = price,
                    amount = amount,
                };
                this.mySubject.OnNext(args);
            });
        });

1 个答案:

答案 0 :(得分:4)

FromEvent有一个特殊的重载。让你的头脑有点傻,但功能签名看起来像:

IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Func<Action<TEventArgs>, TDelegate> conversion, 
                                                         Action<TDelegate> addHandler, 
                                                         Action<TDelegate> removeHandler);

转换函数是这里的重要部分,基本上你告诉Rx你的委托如何映射到具体类型。

在你的场景中,它最终看起来像这样:

Observable.FromEvent<MyDelegate, MyArgs>(
  converter => new MyDelegate(
                  (id, price, amount) => converter(new MyArgs { 
                                                        RequestId = id, 
                                                        Price = price, 
                                                        Amount = amount
                                                       })
               ),
  handler => MyEvent += handler,
  handler => MyEvent -= handler);

那么这一切是做什么的?在内部,它与您正在做的类似(我将从概念上解释它的作用,因为实现稍微复杂一些)。进行新订阅时,将调用转换函数,并将observer.OnNext作为converter参数传入。这个lambda将返回一个新的MyDelegate实例,它包装了我们提供的转换函数((id, price, amount) => ...)。然后将其传递给handler => MyEvent += handler方法。

在每次触发事件之后,它将调用我们的lambda方法并将传递的参数转换为MyArgs的实例,然后将其传递给converter / observer.OnNext

此外,对于所有这些魔法,它还会在完成后清理事件处理程序,优雅地向下传递异常并通过在多个观察者之间共享单个事件处理程序来管理内存。

Source code