Joh*_*ger 7 c# events system.reactive
我正在努力将以下事件转换为IObservable:
public delegate void _dispSolutionEvents_OpenedEventHandler();
event _dispSolutionEvents_OpenedEventHandler Opened;
Run Code Online (Sandbox Code Playgroud)
该活动来自图书馆,所以我无法改变它.IObservable.FromEvent应该做的重载具有以下签名:
public static IObservable<Unit> FromEvent
( Action<Action> addHandler
, Action<Action> removeHandler
)
Run Code Online (Sandbox Code Playgroud)
所以我尝试转换这样的事件:
var opened = Observable.FromEvent
( h => _SolutionEvents.Opened += h
, h => _SolutionEvents.Opened -= h
);
Run Code Online (Sandbox Code Playgroud)
但是编译器并不喜欢_SolutionEvents.Opened += h和_SolutionEvents.Opened += h因为
无法将类型'System.Action'隐式转换为'EnvDTE._dispSolutionEvents_OpenedEventHandler'.
我不认为我可以说,_SolutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(h)因为那时删除不起作用,因为我有一个不同的实例,对吧?
还有另一个Observable.FromEvent带有以下签名的重载:
public static IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>
( Func<Action<TEventArgs>, TDelegate> conversion
, Action<TDelegate> addHandler
, Action<TDelegate> removeHandler
)
Run Code Online (Sandbox Code Playgroud)
这个允许将操作转换为事件处理程序,但似乎只能使用TEventArgs.
Rx是否缺少适当的超载或我错过了什么?
事实证明,使用该FromEvent模式非常容易.
这样做:
var opened = Observable.FromEvent<_dispSolutionEvents_OpenedEventHandler, Unit>(
h => () => h(Unit.Default),
h => _SolutionEvents.Opened += h,
h => _SolutionEvents.Opened -= h);
Run Code Online (Sandbox Code Playgroud)
我用这段代码测试了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();
}
}
Run Code Online (Sandbox Code Playgroud)
它产生以下预期输出:
Opened
值得注意的是,没有IObservable界面,只有一个,IObservable<T>所以你必须返回一些东西.这里的诀窍是转换delegate void _dispSolutionEvents_OpenedEventHandler()为IObservable<Unit>使其工作,这就是它的h => () => h(Unit.Default)作用.
您在这里遇到了类型问题。类型_dispSolutionEvents_OpenedEventHandler不是Action。看起来像Action类型,但其实不是类型Action。
IMO 此事件不符合 .NET 事件标准。object通常,委托将匹配采用发送者参数和EventArg第二个参数的子类的模式。
IE。
public delegate void _dispSolutionEvents_OpenedEventHandler(object sender, EventArgs e);
Run Code Online (Sandbox Code Playgroud)
如果您尝试将 an 附加Action到事件中,您也会发现失败。
Action onOpened = ()=>Console.WriteLine("Opened");
_SolutionEvents.Opened += onOpened; //CS0029 Cannot implicitly convert type 'System.Action' to '_dispSolutionEvents_OpenedEventHandler'
Run Code Online (Sandbox Code Playgroud)
如果你这样做,编译器足够聪明,可以进行一些类型推断;
_SolutionEvents.Opened+= () => Console.WriteLine("Opened");
Run Code Online (Sandbox Code Playgroud)
但是当您使用 Rx 时,您已经输入了类型Action,因此实际上回到了上面的上一个问题。
如果库所有者很好,事件将遵循正常的发送者/事件参数模式。如果做不到这一点,他们至少会将委托指定为一个Action而不是他们自己的客户无参数、无效方法。:-/
因此,由于您所拥有的事件不符合标准 .NET 模式,您将需要为 Rx 提供更多帮助(归咎于您的库提供商而不是 Rx)。
您可以对抗FromEvent/FromEventPattern方法,但由于您的库不符合事件的精神,我建议只简单使用它,Observable.Create至少可以使代码清楚地看到正在发生的事情,并且应该允许下一个用户更好地理解它。
Observable.Create<Unit>(obs =>
{
_dispSolutionEvents_OpenedEventHandler handler = () => obs.OnNext(Unit.Default);
_SolutionEvents.Opened += handler;
return System.Reactive.Disposables.Disposable.Create(() => _SolutionEvents.Opened -= handler);
});
Run Code Online (Sandbox Code Playgroud)