.net - 如何从 "non-standard"事件中获取 Rx 中的 IObservable<T>?

标签 .net vb.net system.reactive

这就是我的意思。假设我正在使用公开事件的 API,但这些事件不遵循标准 EventHandlerEventHandler<TEventArgs>签名。例如,一个事件可能如下所示:

Public Event Update(ByVal sender As BaseSubscription, ByVal e As BaseEvent)

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

Dim updates = Observable.FromEvent(Of UpdateEventArgs)( _
    target:=updateSource, _
    eventName:="Update" _
)

但这不起作用,因为 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))

不过,我必须承认,我很难理解这一点 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;

这里棘手的部分是,似乎某种类派生自 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
);

首先:我能说清楚吗?其次:我是否正确地说,使用 VB 9,如果不编写自己的方法,确实无法完成上述任务?

我几乎感觉自己一开始就从完全错误的角度来处理这个问题。但我真的不确定。

最佳答案

也许您可以为自定义事件签名添加您自己的实现?

public interface ICustomEvent<TSource, TArgs>
{
    public TSource Source { get; }
    public TArgs EventArgs { get; }
}

public interface CustomEvent<TSource, TArgs> : ICustomEvent<TSource, TArgs>
{
    public TSource Source { get; set; }
    public TArgs EventArgs { get; set; }
}

public static class ObservableEx
{
    public static IObservable<ICustomEvent<TSource, TArgs>> FromCustomEvent(
        Action<Action<TSource, TArgs>> addHandler, 
        Action<Action<TSource, TArgs>> removeHandler)
    {
        return Observable.CreateWithDisposable(observer =>
            {
                Action<TSource, TArgs> eventHandler = (s,a) => 
                    observer.OnNext(new CustomEvent<TSource,TArgs>(s,a));

                addHandler(eventHandler);

                return Disposable.Create(() => removeHandler(eventHandler));
            });
    }
}

然后您可以将其用作:

var observable = ObservableEx.FromCustomEvent<BaseSubscription,BaseEvent>(
    h => updateSource.Update += h,
    h => updateSource.Update -= h
);

关于.net - 如何从 "non-standard"事件中获取 Rx 中的 IObservable<T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2915051/

相关文章:

c# - 类型转换的性能

.net - Visual Studio 2008 调试器不报告一些常见错误

mysql - 如何限制可以输入到 Visual Basic 文本框的数据类型?

asp.net - InnerException 消息为 'Maximum number of items that can be serialized or deserialized in an object graph is ' 65536'。

c# - .NET 编程 - 我可以从我的 VB.NET 项目访问 C-Sharp 项目的成员吗?

c# - 没有对订阅者的空调用的 Rx 缓冲区

c# - 在 .NET 图表的 X 轴中仅使用自定义标签

.net - URL 编码 URL

c# - ReactiveExtensions 和异步服务方法?

f# - 从分组的 Observable 中提取值