2

I'm wondering about something. Let's say I have an event named SomethingChanged with 2 parameters. first is the sender which fires the event. second one is just a number.

Case 1:

I defined this event in SenderClass:

public event Action<SenderClass, int> SomethingChanged;

Normally I can attach the event handler like this:

item.SomethingChanged += (sender, p) =>
{
    if (p == 1) sender.F1();
    else sender.F2();
};

Case 2:

But if I remove the sender parameter:

public event Action<int> SomethingChanged;

it does not change a thing and I still can use it:

item.SomethingChanged += p =>
{
    if (p == 1) item.F1();
    else item.F2();
};

It's obvious to me that by removing sender the following usage is no longer feasible:

item.SomethingChanged += item_SomethingChanged;

private void item_SomethingChanged(SenderClass sender, int p)
{
    if (p == 1) sender.F1();
    else sender.F2();
}

Question:

But the thing I'm curious about is How the compiler finds about that sender in Case2? Does it use reflection or do they both translate into the same assembly code? Or?

Bizhan
  • 16,157
  • 9
  • 63
  • 101
  • 1
    Are you sure your second snippet compiles? Post your event declaration and delegate definition. – Sriram Sakthivel Apr 23 '14 at 10:08
  • 1
    "How the compiler finds about that sender" - it doesn't. You're referencing a captured outer variable called `item`. You could have written your original case 1 to use `item` and completely ignored the `sender` parameter - if the assumption that the `sender` will always be the same object is *valid*. If it's not valid, then you're losing information in case 2, and you cannot find out what *would* have been sent as `sender`. – Damien_The_Unbeliever Apr 23 '14 at 10:23
  • Generally you can use any variable in a lambda expression that is defined in an enclosing block. – Bizhan Apr 23 '14 at 10:27
  • 1
    [That is called closure](http://stackoverflow.com/questions/5438307/detailed-explanation-of-variable-capture-in-closures) – Sriram Sakthivel Apr 23 '14 at 10:27

1 Answers1

3

That's because in your second case, you are using the item local variable, which is accessible from your lambda. The compiler doesn't need to find out about a sender variable because it is simply not being used - nor it is being provided, it simply does not exist at all in your second case.

From Variable Scope in Lambda Expressions:

Lambdas can refer to outer variables that are in scope in the enclosing method or type in which the lambda is defined. Variables that are captured in this manner are stored for use in the lambda expression even if variables would otherwise go out of scope and be garbage collected. An outer variable must be definitely assigned before it can be consumed in a lambda expression.

If you want to get an idea of how variable capturing happens, check the answer from the link provided by @Sriram in the comments.

Community
  • 1
  • 1
jnovo
  • 5,659
  • 2
  • 38
  • 56