简体   繁体   中英

Observable.FromEventPattern(addHandler, removeHandler ) - simplification?

When creating an observable from an event, it looks like the following is the most common way:

var o = Observable.FromEventPattern(h => source.Event += h,
                                    h => source.Event -= h);

I find this form a little tedious in some cases where I would like to handle multiple events in the same way. But that doesn't look to easy, since the event it self seems impossible to parameterize, as shown in this non-compiling code:

private IObservable MakeAnObservableFromThisEvent(Event event)
{
    return Observable.FromEventPattern(h => event += h,
                                        h => event -= h);

}

private void MakeAlotOfObservables(object source)
{
    MakeAnObservableFromThisEvent(source.OneEvent);
    MakeAnObservableFromThisEvent(source.AnotherEvent);
    MakeAnObservableFromThisEvent(source.ThirdEvent);

    //or even
    MakeAnObservableFromThisEvent(() => source.ThirdEvent);
}

Of cause there is the 'event name'-overload:

var o = Observable.FromEventPattern< >(source, "Event");

but then there is this thing with more or less magic strings...

Is there away of optimizing this code? Or is this just the way things are?

The problem is that event handlers have "value-type" semantics (like strings) and so passing them as parameters is only useful if you intend to invoke them. Adding new handlers effectively creates a new delegate instance and the original is not modified.

Then only really viable method to add and remove handlers and maintain type safety at the same time is with the syntax you showed first in your question.

var o =
    Observable
        .FromEventPattern(
            h => source.Event += h,
            h => source.Event -= h);

However, there is another option that I've used quite a bit - and that's using extension methods.

If I have this class:

public class Foo
{
    public event EventHandler<EventArgs> Click;
}

I can write an extension method:

public static class FooEx
{
    public static IObservable<EventPattern<EventArgs>> Clicks(this Foo source)
    {
        return
            Observable
                .FromEventPattern<EventArgs>(
                    h => source.Click += h,
                    h => source.Click -= h);
    }
}

That then allows me to write this:

var foo = new Foo();
foo.Clicks().Subscribe(x => Console.WriteLine("Click!"));

You effectively write the extension method once per type and event and then can use it where ever you need to with a much improved syntax.

It's not really a direct solution, but the ReactiveUI-Events basically implements what @Enigmativity suggests for the entire framework. So you can do something like:

Observable.Merge(
    Foo.Events().Clicked.Select(_ => Unit.Default),
    Foo.Events().KeyUp.Select(_ => Unit.Default));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM