1

Follow up to my question here:

According to a comment made -

The compiler creates a class member with a fictitious name and attaches it just as you would attach a declared method.

I do not fully comprehend what this means but I can verify that if instead of saying

Foo.Bar += (S, E) => { /*Code Goes Here*/ }

I instead say

Foo.Bar += FooBar;

private void FooBar( object sender, EventArgs e ){
    /*Code Goes Here*/
}

then Event.Target changes from WhatIsThis.App.<>c to WhatIsThis.App.

That's awesome but I can't guarantee that I will always write an actual method to attach to an event handler.

In the cases where I do use an anonymous method, is there a way to extract the real target, or am I just pigeonholed into using defined methods (I mean, I can live with that I guess but if there's some high-tech sorcery that I can employ to extract the real target, then I'm all for it ).

Community
  • 1
  • 1
Will
  • 3,413
  • 7
  • 50
  • 107
  • What's wrong with using the first parameter (`sender`)? – spender Mar 02 '16 at 22:58
  • @spender The problem is that in some cases, sender will be null. Sender is not implied to be the target anyway. That would be like sending a package from myself to myself, no? – Will Mar 02 '16 at 23:01
  • ...was just catching up on your previous question... ignore the previous comment. – spender Mar 02 '16 at 23:03

1 Answers1

4

do not fully comprehend what this means

Let's fix your comprehension. Suppose you have:

class C 
{
  int x;
  void M(int y) 
  { 
    int z = GetZ(); 
    Func<int, int> f = q => q + x + y + z;
    ... 

f is a delegate. It has a receiver and a method that is a method of the receiver. (Note, this is not actually a strict requirement but the corner case is obscure for our purposes today.)

What type is the receiver that has that method?

Can it be C, with the receiver equal to this? No. Why not? Because then how do we keep track of the value of y and z? There could be a different value for every invocation of M, so the receiver cannot be this.

What the compiler does is generates a new class:

class C 
{
  int x;
  class Locals
  {
    public C __this;
    public int y;
    public int z;
    public int A(int q) { return q + __this.x + y + z; }
  }

  void M(int y) 
  {
    Locals locals = new Locals();
    locals.__this = this;
    locals.y = y;
    locals.z = GetZ(); 
    Func<int, int> f = locals.A;
    ... 

So what is the receiver? the value of locals. What is the method? A.

Of course both Locals and A are given crazy names so that you cannot call them by accident.

In the cases where I do use an anonymous method, is there a way to extract the real target

You are extracting the real receiver, I promise.

'm working on an extension to do some things with Event Handlers and I need to be able to discern what an event handlers target is

Please don't do that. The receiver of an event handler is an implementation detail of the code that provided the handler. It's not there for you to make decisions on. Compilers are well within their rights to make any choice they like when generating a receiver for an event handler, and they do. Consider what happens if the event handler was created inside an iterator block, or an async method, for example. Or the event is being subscribed by some reactive extensions code that is applying sequence operations to the event. Again, the compiler will be generating classes all over the place. You can't rely on the class being something "sensible".

The thing you can rely on is: the subscriber wished the given method to be called when something happened. That's the contract you must obey; don't try to second-guess the subscriber.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Okay thanks for helping me become less ignorant. I should specify - the reason I want to know what the target is ( `ISynchronizeInvoke` vs `DispatcherObject` ) is because I want to be able to gracefully handle cross-thread tomfoolery without things exploding ( so being able to call `ISynchronizeInvoke.InvokeRequred` and `ISynchronizeInvoke.Invoke( ... )` as well as `DispatcherObject.Dispatcher.CheckAccess( )` and `DispatcherObject.Dispatcher.Invoke( ... )` with relative impunity would go a long way towards helping me with this. – Will Mar 02 '16 at 23:07
  • @Will: If the contract that the observer and the observable have with each other is that the observable will source an event on a thread context other than that in which the observer gave the handler to the observable then the authors of those two classes are required to get together and sort it out amongst themselves. It would be surprising if a handler was called back in a different context than that in which the handler was provided. – Eric Lippert Mar 02 '16 at 23:49