使用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); });