使用 Observable.FromEvent 转换没有 EventArgs 的事件
Convert event without EventArgs using Observable.FromEvent
我正在努力将以下事件转换为 IObservable
:
public delegate void _dispSolutionEvents_OpenedEventHandler();
event _dispSolutionEvents_OpenedEventHandler Opened;
活动来自图书馆,所以我无法更改。
应该执行的 IObservable.FromEvent
重载具有以下签名:
public static IObservable<Unit> FromEvent
( Action<Action> addHandler
, Action<Action> removeHandler
)
所以我尝试像这样转换事件:
var opened = Observable.FromEvent
( h => _SolutionEvents.Opened += h
, h => _SolutionEvents.Opened -= h
);
但是编译器不喜欢_SolutionEvents.Opened += h
和_SolutionEvents.Opened += h
因为
Cannot implicitly convert type 'System.Action' to '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
)
这个允许将动作转换为事件处理程序,但它似乎只适用于 TEventArgs
。
Rx 是否缺少适当的重载或者我是否遗漏了什么?
您 运行 遇到了类型问题。 _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
方法,但由于你的库不符合事件的精神,我建议只使用 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);
});
事实证明,使用 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();
}
}
它产生以下预期输出:
Opened
值得注意的是没有IObservable
界面,只有一个IObservable<T>
所以你必须return一些东西。这里的技巧是将 delegate void _dispSolutionEvents_OpenedEventHandler()
转换为 IObservable<Unit>
以使其工作,这就是 h => () => h(Unit.Default)
所做的。
我正在努力将以下事件转换为 IObservable
:
public delegate void _dispSolutionEvents_OpenedEventHandler();
event _dispSolutionEvents_OpenedEventHandler Opened;
活动来自图书馆,所以我无法更改。
应该执行的 IObservable.FromEvent
重载具有以下签名:
public static IObservable<Unit> FromEvent
( Action<Action> addHandler
, Action<Action> removeHandler
)
所以我尝试像这样转换事件:
var opened = Observable.FromEvent
( h => _SolutionEvents.Opened += h
, h => _SolutionEvents.Opened -= h
);
但是编译器不喜欢_SolutionEvents.Opened += h
和_SolutionEvents.Opened += h
因为
Cannot implicitly convert type 'System.Action' to '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
)
这个允许将动作转换为事件处理程序,但它似乎只适用于 TEventArgs
。
Rx 是否缺少适当的重载或者我是否遗漏了什么?
您 运行 遇到了类型问题。 _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
方法,但由于你的库不符合事件的精神,我建议只使用 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);
});
事实证明,使用 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();
}
}
它产生以下预期输出:
Opened
值得注意的是没有IObservable
界面,只有一个IObservable<T>
所以你必须return一些东西。这里的技巧是将 delegate void _dispSolutionEvents_OpenedEventHandler()
转换为 IObservable<Unit>
以使其工作,这就是 h => () => h(Unit.Default)
所做的。