在Observable.FromEvent
中拥有这样的签名的目的是什么?例如:
var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
特别是,什么是h
?为什么+=
,然后-=
?我们是从事件还是从事件处理程序进行Observable
?如果来自事件,为什么不只有一个签名,例如:
var appActivated = Observable.FromEvent(Application.Current.Activated);
事件作为参数传递给方法。您可以作为委托人传入事件,但这并不能让您订阅/取消订阅事件。看看埃里克·利珀特的这个答案。
Observable.From
基本上是说"好的,我会给你一个可观察量,它是事件的包装器,但你需要为我提供两个委托:1) 一个委托让我订阅我的处理程序到事件,2) 一个委托让我在需要时取消订阅我的处理程序"。
因此,在这种情况下h => Application.Current.Activated += h
是一个编译为委托的 lambda 表达式。 h
(处理程序)是输入参数,委托获取该输入参数并将其订阅到 Activated
事件。第二个委托是相同的,只是它取消订阅处理程序。
Eren 的回答是正确的;我想确保回答您的所有问题:
特别是,什么是h?
h 是添加和删除处理程序的委托的参数。调用时,h 将是对处理程序委托的引用。
为什么是+=,然后是-=?
可观察量需要能够订阅和取消订阅事件的处理程序。
我们是否从事件或事件处理程序中使可观察
?
从事件。
如果来自事件,为什么不只有一个签名,例如:
var appActivated = Observable.FromEvent(Application.Current.Activated);
?
因为这将传递处理程序,而不是事件。"事件"是三件事:调用处理程序列表的能力、向列表中添加新处理程序的能力以及从列表中删除处理程序的能力。 可观察量需要最后两个;你的建议是通过第一个。 因此,可观察量需要执行最后两个操作的委托。
可观察量是 .NET 中的一类类型 - 这意味着您可以保留对它们的引用,并将它们作为参数传递给您喜欢的任何构造函数/方法。
事件不是第一类类型。它们只能在可以引用其包含对象的作用域中附加和分离。
所以这意味着我不能这样做:
public void SomeMethod(EventHandler handler)
{
handler += (s, e) => { /* Handler Code */ };
}
public void SomeOtherMethod()
{
SomeMethod(Application.Current.Activated);
}
如果我尝试出现错误:
事件"应用程序已激活"只能出现在 += 或 -= 的左侧
这应该让你知道为什么你不能做var appActivated = Observable.FromEvent(Application.Current.Activated);
。
那么,我该如何解决此问题以在SomeMethod
中附加事件?
方法如下:
public void SomeMethod(Action<EventHandler> addHandler)
{
addHandler((s, e) => { /* Handler Code */ });
}
public void SomeOtherMethod()
{
SomeMethod(h => Application.Current.Activated += h);
}
基本上,在方法SomeMethod
中,参数不再是EventHandler
,而是Action<EventHandler>
。这意味着我不再尝试传递事件本身 - 而是传递一种方式,让被调用的代码将自身附加到我的事件。调用SomeMethod
h
是一个承诺,将来如果我有一个有效的处理程序,那么我可以通过调用Action<EventHandler>
来附加它。
因此,假设我现在想编写一些知道如何附加和分离事件的代码。我现在需要这段代码:
public void SomeMethod(Action<EventHandler> addHandler, Action<EventHandler> removeHandler)
{
EventHandler handler = (s, e) => { /* Handler Code */ };
addHandler(handler);
/* Some Intervening Code */
removeHandler(handler);
}
public void SomeOtherMethod()
{
SomeMethod(h => Application.Current.Activated += h, h => Application.Current.Activated -= h);
}
在/* Some Intervening Code */
代码中,处理程序被附加,在分离之后。
这就把我们带到了你的问题中的代码:
var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
这与上面的SomeMethod
调用非常相似 - FromEvent
需要一种方法来附加和分离事件。h
是一个承诺,上面写着"嘿,FromEvent
,如果你能提供一个处理程序,当你将来需要它时,我保证这段代码会正确附加它。或者,视情况而定,分离。
现在,只是为了有点迂腐,你的代码实际上应该是:
IObservable<EventPattern<EventArgs>> appActivated =
Observable
.FromEventPattern<EventHandler, EventArgs>(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
现在我有一个IObservable<EventPattern<EventArgs>>
我可以重写SomeMethod
将其作为参数并像这样编写:
public IDisposable SomeMethod(IObservable<EventPattern<EventArgs>> appActivated)
{
return appActivated.Subscribe(ep => { /* Handler Code */ });
}
现在可以看到Rx的所有功能。.Subscribe
方法不需要对原始事件的包含对象进行任何引用,但它最终会在需要时调用h => Application.Current.Activated += h
来附加和h => Application.Current.Activated -= h
分离。现在,我可以有效地将事件作为 .NET 中的一类类型传递。