#552 – Anonymous Methods Have Access to Local Variables Where They Are Declared
April 2, 2012 7 Comments
When you declare an anonymous method, the body of the method has access to any formal parameter that you declared as part of the anonymous method declaration. For example, in the code fragment before, the body of the method has access to the s parameter.
StringHandlerDelegate del1 = delegate (string s) { Console.WriteLine(s); };
The body of an anonymous method can also make use of any variables visible within the scope where it is defined. In the example below, the method makes use of the local variable rudeNeighbor. The Bark method accepts a delegate and then invokes that delegate, passing back the actual bark noise that the dog makes.
static void Main() { string rudeNeighbor = "Paul"; Dog d = new Dog("Jack", 17); d.Bark(delegate(string s) { Console.WriteLine("Hey {0}: {1}", rudeNeighbor, s); }); }
For completeness, here is the body of the Dog.Bark method:
public void Bark(BarkAtDelegate barkMethod) { barkMethod("Grrrr"); }
The name of this variables in context of delegate: captured variable. See here http://msdn.microsoft.com/en-us/library/0yw3tz5k.aspx
Where is the definition of BarkAtDelegate?
It’s just a delegate that accepts a single string parameter and returns void
A word of caution here. I ran into an issue when storing a delegate (to be executed later) that used a variable in scope. When building a delegate in a loop, the most recent value of that variable is used by the delegate at execution time. For example, this code will result in John being growled at 3 times instead of each of the neighbors being growled at:
static void Main()
{
string[] rudeNeighbors = new string[] { “Paul”, “Ringo”, “John” };
Dog[] dogs = new Dog[] { new Dog(), new Dog(), new Dog() };
int i = 0;
foreach (string rudeNeighbor in rudeNeighbors)
{
dogs[i].BarkMethod = delegate { Console.WriteLine(“Hey {0}: {1}”, rudeNeighbor, “Grrrr”); };
i++;
}
foreach(Dog dog in dogs)
{
dog.Bark();
}
}
class Dog
{
public BarkAtDelegate BarkMethod;
public void Bark()
{
BarkMethod();
}
public delegate void BarkAtDelegate();
}
Sorry for the formatting on that post. I had posted it with tabs, but they didn’t stick.
Is this still the case in C# 5.0? (See https://csharp.2000things.com/2014/06/20/1122-its-okay-to-capture-variables-within-a-foreach-loop/ )
Very nice! I am still using C# 4.0 at the moment, but my company will be moving on to 5.0 or 6.0 very soon, so it’s nice to see I won’t have to deal with this anymore. Thanks!