-1

If I have a method that takes an argument of type Action, for example:

public void Foo(Action bar)
{
    bar?.Invoke();
}

And I wish to pass it a lambda that uses a local variable, e.g.:

private void SomeEvent(object sender, SomeEventArgs e)
{
    foo(() => { e.Cancel = true; });
}

Will this lambda execute as expected with respect to the use of the local variable, in this case, e? What I mean is, When foo() is called and in turn attempts to call the lambda, will it know e? Or will e be out of scope and I should do something like the following instead?

private void SomeEvent(object sender, SomeEventArgs e)
{
    foo((SomeEventArgs a) => { a.Cancel = true; }, e);
}

public void Foo(Action<SomEventArgs> bar, SomeEventArgs e)
{
    bar?.Invoke(e);
}
Toby
  • 9,696
  • 16
  • 68
  • 132
  • `e` would be accessible, the first example you showed didn't worked ? – Ehsan Sajjad Mar 28 '17 at 09:47
  • Why ask us if something will work when you can simply run it for yourself? – jmcilhinney Mar 28 '17 at 09:49
  • It did work in my first test, but I am new to C# and using this as a class's public method so want to be sure I'm doing it correctly rather than relying on a fluke, so that it doesn't come back to haunt me later. – Toby Mar 28 '17 at 09:49
  • 2
    Yes, it should work as expected. This is called "captured variables". Read this post to understand better: http://stackoverflow.com/questions/5438307/detailed-explanation-of-variable-capture-in-closures – vyrp Mar 28 '17 at 09:52
  • @vyrp Variable capture, great! Thank you. Maybe you'd like to make that an answer? – Toby Mar 28 '17 at 09:54
  • I don't know... Normally they say to not just post a link as an answer. – vyrp Mar 28 '17 at 09:55
  • @vyrp True. This directly answers my question though. Maybe you could answer with the link and a small explanation either – Toby Mar 28 '17 at 09:56

2 Answers2

3

This little example shows that the local variable will be changed:

void Main()
{
    int local = 0;

    Foo(() => { local = 55; });
    Console.WriteLine(local);
}

public static void Foo(Action bar)
{
    bar?.Invoke();
}

Output:

55

This example can also be extended to include events:

public class P
{
    public delegate void MyEventDelegate(bool e);

    public event MyEventDelegate MyEvent;

    public void shootEvent() {MyEvent(false);}
}

void Main()
{       
    P p = new P();
    p.MyEvent += MyeventHandler;

    p.shootEvent();
}

public void MyeventHandler(bool b)
{
    Foo(() => { b = true; });
    Console.WriteLine(b);
}

Output:

true

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
2

Yes, it should work as expected. This is called "Variable capture", and is very well explained here.

In your example, the e variable is captured, so it won't go out of scope.

Community
  • 1
  • 1
vyrp
  • 890
  • 7
  • 15