在Observable.FromEvent
中签署此类签名的目的是什么?
对于example:
var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
特别是h
是什么?为什么+=
,然后是-=
?我们从事件或事件处理程序中创建Observable
吗?如果来自事件,为什么不只是签名:
var appActivated = Observable.FromEvent(Application.Current.Activated);
答案 0 :(得分:5)
那是因为没有办法将作为参数传递给方法。您可以将事件作为委托传递,但这不会使您能够订阅/取消订阅该事件。请参阅Eric Lippert的answer。
Observable.From
基本上说“好吧,我会给你一个可以观察到事件的包装物,但你需要给我两个代表:1)一个代表让我订阅我的处理程序到事件,2)代表我在需要时取消订阅我的处理程序“。
所以在这种情况下h => Application.Current.Activated += h
是一个lambda表达式,它被编译成一个委托。 h
(handler)是输入参数,委托获取该输入参数并将其记录到Activated
事件。第二个委托是相同的,除了它取消订阅处理程序。
答案 1 :(得分:3)
特别是什么是h?
h是添加和删除处理程序的代理的参数。调用时,h将是对处理程序委托的引用。
为什么+ =,然后 - =?
observable需要能够为事件订阅和取消订阅处理程序。
我们是从事件还是从事件处理程序创建Observable?
来自活动。
如果来自活动,为什么不只是签名:
var appActivated = Observable.FromEvent(Application.Current.Activated);
?
因为那会传递处理程序,而不是事件。一个"事件"有三件事:调用处理程序列表的能力,向列表添加新处理程序的能力,以及从列表中删除处理程序的能力。观察者需要最后两个;你的建议是通过第一个。所以observable需要代表做最后两个。
答案 2 :(得分:2)
Observables是.NET中的第一类类型 - 意味着您可以保留对它们的引用并将它们作为参数传递给您喜欢的任何构造函数/方法。
事件不一流类型。它们只能在您可以引用其包含对象的范围内进行附加和分离。
所以这意味着我不能这样做:
public void SomeMethod(EventHandler handler)
{
handler += (s, e) => { /* Handler Code */ };
}
public void SomeOtherMethod()
{
SomeMethod(Application.Current.Activated);
}
如果我尝试,我会收到错误:
事件'Application.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>
。这意味着我不再试图传递事件本身 - 相反,我正在通过一种方式让被调用的代码将自己附加到我的事件中。 h
调用中的SomeMethod
是承诺,如果我有一个有效的处理程序,将来我可以通过调用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中的第一类类型传递。