Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable.FromEvent & CreateDelegate param mapping

I was looking at the implemention of

Observable.FromEvent<TEventHandler, TEventHandlerArgs>(add, remove)

and I'm struggling to grasp how it works. Lets says that TEventHandler is the standard:

public delegate void EventHandler(object sender, EventArgs e);

then the code that is puzzling me is:

TEventHandler d = (TEventHandler) Delegate.CreateDelegate(
    typeof (TEventHandler),
    (object) new Action<EventArgs>(observer.OnNext),
    typeof (Action<EventArgs>).GetMethod("Invoke"));

(n.b I've specialised this generic code to this specific example instance.)

How is it that CreateDelegate is creating a delegate of signature (obj, args) that is bound to an invoke method of signature (args) on the action? Where is obj going?

It feels a bit like it might be around having an open delegate on action and we are coercing the 'this' to be 'firstArguemnt' from CreateDelegate and allowing the args to fall through. If so feels kinda dirty?

like image 204
DanH Avatar asked Nov 02 '12 18:11

DanH


People also ask

What is fromEvent in RxJS?

RxJS fromEvent() operator is a creation operator used to give the output as an observable used on elements that emit events, such as buttons, clicks, etc.

What is fromEvent in angular?

fromEvent - Angular. Creates an Observable that emits events of a specific type coming from the given event target. The DOM EventTarget, Node. js EventEmitter, JQuery-like event target, NodeList or HTMLCollection to attach the event handler to.

Which of the following will create an observable from an event using RX JS in angular?

Angular provides FromEvent method to create an observable from DOM events directly.

What is RxJS observable?

RxJS Operators An observable is a function that creates an observer and attaches it to the source where values are expected from, for example, clicks, mouse events from a dom element or an Http request, etc.


1 Answers

Let's break it down:

Firstly, decompiling Rx v2.0.3 doesn't seem to have a Observable.FromEvent<TEventHandler, TEventHandlerArgs>(add, remove) method, and neither does Rx v 1.1 which I happened to have lying around. I'm going to assume you mean the nearest match I can find, which is this:

public static IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler)

Looking at the decompiled source for Rx 1.1 (the 2.0 source has gone all architecture astronaut on us and is full of indirection which makes it much harder to follow) The actual code snippet using reflector to decompile is this:

Action<TEventArgs> o = new Action<TEventArgs>(observer.OnNext);
    TDelegate d = CreateDelegate<TDelegate>(o,
        typeof(Action<TEventArgs>).GetMethod("Invoke"));

    addHandler(d);

So, the question:

How is it that CreateDelegate is creating a delegate of signature (obj, args) that is bound to an invoke method of signature (args) on the action? Where is obj going?

I'm not sure if I've understood quite correctly, but it seems like the question specifically is something like How does CreateDelegate<TDelegate>(o, typeof(Action<TEventArgs>).GetMethod("Invoke") produce a method with only the args parameter - what happens to the o object?

What's happening is that yes, the o object is being passed as object firstArgument to the internal .NET framework method.

public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure)

This method "binds" the firstArgument as basically being the this pointer for the returned method. Internally it will store a reference to the firstArgument somewhere inside the delegate object. We can't see inside that as it's an internal .NET implementation detail and so it can do all sorts of odd things and break rules where it pleases.

It feels a bit like it might be around having an open delegate on action and we are coercing the 'this' to be 'firstArguemnt' from CreateDelegate and allowing the args to fall through. If so feels kinda dirty?

Yes, that's pretty much exactly what's happening. This is what that CreateDelegate function is designed to do.
Except it gets even dirtier than that. CreateDelegate simply returns an object of type Delegate - we have no type safety on the method args, etc - and then the code casts it into a TDelegate - this works because delegate is special and you can cast it to any function type that has the same "shape". As above, it's an internal .NET implementation detail and so it can do all sorts of weird things :-)

like image 148
Orion Edwards Avatar answered Sep 20 '22 02:09

Orion Edwards