使用Observable.FromEvent转换事件而不使用EventArgs
我正在努力将以下事件转换为IObservable
:
public delegate void _dispSolutionEvents_OpenedEventHandler(); event _dispSolutionEvents_OpenedEventHandler Opened;
该活动来自图书馆,所以我无法改变它。 应该执行它的IObservable.FromEvent
的重载具有以下签名:
public static IObservable FromEvent ( Action addHandler , Action removeHandler )
所以我尝试转换这样的事件:
var opened = Observable.FromEvent ( h => _SolutionEvents.Opened += h , h => _SolutionEvents.Opened -= h );
但编译器不喜欢_SolutionEvents.Opened += h
和_SolutionEvents.Opened += h
因为
无法将类型’System.Action’隐式转换为’EnvDTE._dispSolutionEvents_OpenedEventHandler’。
我不认为我只能说_SolutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(h)
因为那时删除不起作用,因为我有一个不同的实例,对吧?
Observable.FromEvent
还有另一个重载,带有以下签名:
public static IObservable FromEvent ( Func<Action, TDelegate> conversion , Action addHandler , Action removeHandler )
这个允许将操作转换为事件处理程序,但它似乎只适用于TEventArgs
。
Rx是否缺少适当的过载或我错过了什么?
事实certificate,使用FromEvent
模式非常容易。
这样做:
var opened = Observable.FromEvent<_dispSolutionEvents_OpenedEventHandler, Unit>( h => () => h(Unit.Default), h => _SolutionEvents.Opened += h, h => _SolutionEvents.Opened -= h);
我用这段代码测试了observable:
void Main() { var _SolutionEvents = new Foo(); var opened = Observable.FromEvent<_dispSolutionEvents_OpenedEventHandler, Unit>(h => () => h(Unit.Default), h => _SolutionEvents.Opened += h, h => _SolutionEvents.Opened -= h); opened.Subscribe(x => Console.WriteLine("Opened")); _SolutionEvents.OnOpened(); } public delegate void _dispSolutionEvents_OpenedEventHandler(); public class Foo { public event _dispSolutionEvents_OpenedEventHandler Opened; public void OnOpened() { this.Opened?.Invoke(); } }
它产生以下预期输出:
开业
值得注意的是,没有IObservable
接口,只有IObservable
所以你必须返回一些东西。 这里的技巧是将delegate void _dispSolutionEvents_OpenedEventHandler()
转换为IObservable
以使其工作,这就是h => () => h(Unit.Default)
作用。
你在这里遇到了一个类型的问题。 _dispSolutionEvents_OpenedEventHandler
类型不是Action
。 它看起来像Action
类型,但它不是Action
类型。
IMO此事件不符合事件的.NET标准。 通常,委托将匹配为第二个参数获取sender object
参数和EventArg
子类的模式。
即。
public delegate void _dispSolutionEvents_OpenedEventHandler(object sender, EventArgs e);
如果您尝试将Action
附加到事件,您会发现它也失败了。
Action onOpened = ()=>Console.WriteLine("Opened"); _SolutionEvents.Opened += onOpened; //CS0029 Cannot implicitly convert type 'System.Action' to '_dispSolutionEvents_OpenedEventHandler'
如果你这样做,编译器足够聪明,可以做一些类型推断;
_SolutionEvents.Opened+= () => Console.WriteLine("Opened");
但是当你使用Rx时,你已经输入了Action
类型,所以有效地回到了上面的上一个问题。
如果库所有者很好,事件将遵循正常的sender / eventArgs模式。 如果做不到这一点,他们至少会将委托指定为一个Action
而不是他们自己的客户无参数,void方法。 : – /
因此,由于您所遇到的事件不符合标准的.NET模式,您需要为Rx提供更多的手持设备(责怪您的库提供者而不是Rx)。
你可以对抗FromEvent
/ FromEventPattern
方法,但由于你的库不符合Event的精神,我建议你只需要使用Observable.Create
,这至少可以让代码明显地发生了什么,并且应该允许下一个用户更好地理解它。
Observable.Create(obs => { _dispSolutionEvents_OpenedEventHandler handler = () => obs.OnNext(Unit.Default); _SolutionEvents.Opened += handler; return System.Reactive.Disposables.Disposable.Create(() => _SolutionEvents.Opened -= handler); });