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?
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.
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.
Angular provides FromEvent method to create an observable from DOM events directly.
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.
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 :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With