如何从"非标准"事件中获取Rx中的IObservable <T>?

Dan*_*Tao 6 .net vb.net system.reactive

这就是我的意思.假设我正在使用暴露事件的API,但这些事件不遵循标准EventHandlerEventHandler<TEventArgs>签名.一个事件可能看起来像这样,例如:

Public Event Update(ByVal sender As BaseSubscription, ByVal e As BaseEvent)
Run Code Online (Sandbox Code Playgroud)

现在,通常情况下,如果我想IObservable<TEventArgs>从事件中获取,我可以这样做:

Dim updates = Observable.FromEvent(Of UpdateEventArgs)( _
    target:=updateSource, _
    eventName:="Update" _
)
Run Code Online (Sandbox Code Playgroud)

但是,这并不工作,因为该Update事件不是EventHandler<UpdateEventArgs>-事实上,也就是没有UpdateEventArgs-它基本上只是自己的事.

很显然,我可以定义我自己从类派生EventArgs(即UpdateEventArgs),写另一个类来包装对象提供的Update事件,给包装类它自己的 Update事件一个EventHandler<UpdateEventArgs>,并得到一个IObservable<UpdateEventArgs>那个.但这是令人讨厌的工作量.

有没有办法IObservable<[something]>从这样的"非标准"事件中创建一个或者我运气不好?


更新:从Jon Skeet的回答中,我在下面的重载方向上轻推Observable.FromEvent:

Function FromEvent(Of TDelegate, TEventArgs As EventArgs)( _
    conversion As Func(Of EventHandler(Of TEventArgs), TDelegate), _
    addHandler As Action(Of TDelegate), _
    removeHandler As Action(Of TDelegate) _
) As IObservable(Of IEvent(Of TEventArgs))
Run Code Online (Sandbox Code Playgroud)

不过我不得不承认,我无法绕过那Func(Of EventHandler(Of TEventArgs), TDelegate)部分.它似乎倒退了我(?).显然,我只是缺少一些东西......

无论如何,如果它有所帮助,我认为这就是等效的C#代码的样子(我将非常诚实:我不确定.即使我一般更喜欢C#,这个代码是一个人的工作我的同事们主要用VB.NET编写; VB.NET允许多种语法来声明事件):

// notice: not an EventHandler<TEventArgs>
public delegate void UpdateEventHandler(BaseSubscription sender, BaseEvent e);

// not 100% sure why he did it this way
public event UpdateEventHandler Update;
Run Code Online (Sandbox Code Playgroud)

这里棘手的部分是,无论如何,某种类派生似乎EventArgs都是必要的.在我正在使用的API中,没有这样的类.所以,最低限度,我必须写一个.但这应该是相当微不足道的(基本上是一个属性:) BaseEvent.

最后,我假设这个重载所需的代码在C#中看起来像这样:

var updates = Observable.FromEvent<UpdateEventHandler, UpdateEventArgs>(
    // conversion (Func<EventHandler<UpdateEventArgs>, UpdateEventHandler>)
    handler => (sender, e) => handler(sender, new UpdateEventArgs(e)),
    // addHandler (Action<UpdateEventHandler>)
    handler => updateSource.Update += handler,
    // removeHandler (Action<UpdateEventHandler>)
    handler => updateSource.Update -= handler
);
Run Code Online (Sandbox Code Playgroud)

首先:我是否直截了当?第二个问题:我是否正确地说使用VB 9,如果不编写自己的方法,真的没有办法完成上述操作?

我几乎觉得我从完全错误的角度开始接近这个问题.但我真的不确定.

Jon*_*eet 1

也许可以使用此签名:

Public Shared Function FromEvent(Of TDelegate, TEventArgs As EventArgs) ( _
    conversion As Func(Of EventHandler(Of TEventArgs), TDelegate), _
    addHandler As Action(Of TDelegate), _
    removeHandler As Action(Of TDelegate) _
) As IObservable(Of IEvent(Of TEventArgs))
Run Code Online (Sandbox Code Playgroud)

这里,TDelegate将是事件的委托类型(我无法立即从你的声明中看出 - C# 事件声明看起来不太像那样,而且我担心我不知道足够的 VB 来解密它,但是我确信某处有一个委托类型)。TEventArgs将是事件参数的类型(BaseEvent我认为应该在这里执行)。您需要提供一个从EventHandler(Of BaseEvent)到您的委托类型的转换器 - 这可能只是一个 lambda 表达式,用于调用给定的事件处理程序并将参数传递给它。添加和删​​除操作将是正常的事件订阅代码 - 但表示为委托。

不幸的是,我的 VB 还不够好,无法清晰地表达所有这些 - 或者确实无法知道 VB 9 或 10 中可以轻松获得多少内容。我知道这一切在 C# 中会是什么样子......如果你能给我一个简短的但C# 中的完整示例,让我填写订阅位,我当然可以做到这一点...