Observable.FromEvent 签名

Observable.FromEvent signature

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);

那是因为无法将事件作为参数传递给方法。您可以作为 delegate 传递事件,但这并不能使您能够 subscribe/unsubscribe 参与事件。请参阅 Eric Lippert 的 answer

Observable.From 基本上就是 "Ok, I will give you an observable that is a wrapper around the event, but you need to provide me with two delegates: 1) a delegate for me to subscribe my handler to the event, and 2) a delegate for me to unsubscribe my handler when I need to"。

所以在这种情况下,h => Application.Current.Activated += h 是一个编译成委托的 lambda 表达式。 h(处理程序)是输入参数,委托接受该输入参数并将其订阅到 Activated 事件。第二个委托是同一件事,只是它取消了处理程序的订阅。

艾伦的回答正确;我想确保您的所有问题都得到解答:

In particular, what is h?

h 是添加和删除处理程序的委托的参数。调用时,h 将是对处理程序委托的引用。

And why +=, then -=?

可观察对象需要能够订阅和取消订阅事件的处理程序。

Do we make Observable from event or from event handler?

来自一个事件。

If from event, why not just have a signature like: var appActivated = Observable.FromEvent(Application.Current.Activated); ?

因为那会传递处理程序,而不是事件。 "event" 是三件事:调用处理程序列表的能力、向列表添加新处理程序的能力以及从列表中删除处理程序的能力。 observable 需要最后两个;你的建议是先通过。所以 observable 需要代表做最后两个。

Observable 是 .NET 中的第一个 class 类型 - 这意味着您可以保留对它们的引用并将它们作为参数传递给您喜欢的任何 constructor/method。

事件是不是 first-class 类型。它们只能在您可以引用其包含对象的范围内附加和分离。

所以这意味着我不能这样做:

    public void SomeMethod(EventHandler handler)
    {
        handler += (s, e) => { /* Handler Code */ };
    }

    public void SomeOtherMethod()
    {
        SomeMethod(Application.Current.Activated);
    }

如果我尝试这样做,我会收到错误消息:

The event 'Application.Activated' can only appear on the left hand side of += or -=

这应该让你知道为什么你不能做到 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 是一个承诺 "hey, FromEvent, if you can provide a handler, when you need it in the future, I promise that this code will attach it correctly." 或者,视情况而定。

现在,为了有点迂腐,您的代码实际上应该是:

        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 中作为 first-class 类型有效地传递事件。