如何在不符合标准.NET事件模式的情况下将事件转换为IObservable

pet*_*757 5 c# system.reactive

我有一个看起来像这样的代表:

public delegate void MyDelegate(int arg1, int arg2);
Run Code Online (Sandbox Code Playgroud)

一个看起来像这样的事件:

public event MyDelegate SomethingHappened;
Run Code Online (Sandbox Code Playgroud)

是否有一些简单的方法为此事件创建IObservable序列?我想做这样的事情(但它不会编译):

var obs = Observable.FromEventPattern<int, int>(this, "SomethingHappened");
var subscription = obs.Subscribe(x,y => DoSomething(x, y));
Run Code Online (Sandbox Code Playgroud)

....

private void DoSomething(int value1, int value2)
{
...
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*rld 9

有一种方法可以使用Observable.FromEvent如下方法.

让我们创建一个类Test来封装委托和事件定义:

public class Test
{   
    public delegate void MyDelegate(int arg1, int arg2);

    public event MyDelegate SomethingHappened;

    public void RaiseEvent(int a, int b)
    {
        var temp = SomethingHappened;
        if(temp != null)
        {
            temp(a, b);
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

现在,因为委托有两个没有整齐地打包到子类中的参数EventArgs,我们必须使用转换函数将它们打包成合适的包含类型.如果你记得OnNext方法的签名IObservable应该清楚为什么我们必须这样做 - 我们只能在这里提供一个参数.

你可以为此创建自己的类型,但我会懒惰并使用Tuple<int,int>.然后我们可以使用Observable.FromEvent转换函数的重载,如下所示:

var test = new Test();

var obs = Observable.FromEvent<Test.MyDelegate, Tuple<int,int>>(
    handler => (a, b) => handler(Tuple.Create(a,b)),
    h => test.SomethingHappened += h,
    h => test.SomethingHappened -= h
);
Run Code Online (Sandbox Code Playgroud)

为了清楚起见,我们在第一个参数中提供的是一个函数,它接受一个OnNext处理程序(在这种情况下是类型Action<Tuple<int,int>>)并返回一个可以订阅事件(类型MyDelegate)的委托.将为每个事件调用此委托,并依次调用从Subscribe调用传入的OnNext处理程序.因此,我们最终会得到一个类型的流IObservable<Tuple<int,int>>.

有了obs,我们可以这样订阅:

var subscription = obs.Subscribe(x => Console.WriteLine(x.Item1 + " " + x.Item2));
Run Code Online (Sandbox Code Playgroud)

并测试:

test.RaiseEvent(1, 2);
Run Code Online (Sandbox Code Playgroud)