这就是我的意思。假设我正在使用公开事件的 API,但这些事件不遵循标准 EventHandler
或EventHandler<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/