A previous post warned of some of the dangers of using Anonymous methods in C#. Yes, it’s true you can get yourself into serious trouble with these C# treats. But as you play with them some more, you can actually see that they are much more fun and less scary than you might first think.
One of the first things you need to realize when anonymous methods are created is that they capture / hijack variables that are used in that anonymous method from the scope that they were originally in. So yes, modifying the variable from a particular scope is going to change its value for everyone else within that same scope as well, regardless of which block it is executed from. This is very different from the Java way of doing things (as I understand) where a variable that is accessed from an inner class must be declared as final, read-only, uninteresting. That’s not to say that you can’t do the same thing in Java, but one dimensional arrays are such a pain. I digress.Here’s a starting example of a toy anonymous delegate from a rather good source:
class Program
{
delegate void foo();
static void Main(string[] args)
{
// First build a list of actions
List
for (int counter = 0; counter < 10; counter++)
{
actions.Add(delegate { Console.WriteLine(counter); });
}
// Then execute them
foreach (foo action in actions)
{
action();
}
}
}
At first, running this code doesn't seem to do what you expected. Because the variable is used in the delegate, it is of course "captured". However, it is only declared once in an outer scope, so the same variable will be used each time the delegate is called. Mentally unrolling the loop might even help to make more sense because you see that only one variable is actually being used. In order for each delegate to get a different value, each delegate must get a copy of the variable like so:
class Program
{
delegate void foo();
static void Main(string[] args)
{
// First build a list of actions
List
for (int counter = 0; counter < 10; counter++)
{
int capture = counter;
actions.Add(delegate { Console.WriteLine(capture); });
}
// Then execute them
foreach (foo action in actions)
{
action();
}
}
}
Now into the nitty gritty. The cool part about the two code examples is that the generated anonymous classes that implement the anonymous delegates are essentially identical; the only difference is where the class is (apparently) declared and created. First think about what I mean when I say that. Like before, how / where could you declare two of the same classes in order to get different results. Look at the next two code examples with implemented fantasy classes and the above behavior should make more sense.
Here's some fantasy code that might represent the first code example:
class Program
{
delegate void foo();
private class __FantasyClass01
{
public int counter;
public void del01()
{
Console.WriteLine(this.counter);
}
}
static void Main(string[] args)
{
// First build a list of actions
List
{
Where there are various lawsuits submitted with relevant complaints, with the theory to improve the proceedings Multi-district lawsuit can be used. deeprootsmag.org viagra for sale cheap When students share their experiences which may be something like losing their favorite pet, others are then asked how they might feel so empathy is shared for the person viagra no prescription to get through erectile dysfunction. Move Your Muscles: No, we are not asking you to roll generic levitra no prescription yourself in dirt. Kids, ladies, and individuals over 65 years of age: Daily 25mg with the same time gap as above. pfizer viagra samples __FantasyClass01 fc01 = new __FantasyClass01();
for (fc01.counter = 0; fc01.counter < 10; fc01.counter++)
{
actions.Add(fc01.del01);
}
}
// Then execute them
foreach (foo action in actions)
{
action();
}
}
}
And by contrast the second code example:
class Program
{
delegate void foo();
private class __FantasyClass01
{
public int capture;
public void del01()
{
Console.WriteLine(this.capture);
}
}
static void Main(string[] args)
{
// First build a list of actions
List
for (int counter = 0; counter < 10; counter++)
{
__FantasyClass01 fc01 = new __FantasyClass01();
fc01.capture = counter;
actions.Add(fc01.del01);
}
// Then execute them
foreach (foo action in actions)
{
action();
}
}
}
Running both of these examples should give you the same exact results as the first examples that hide the C# wizardry. Notice that the fantasy classes are declared and created at the same scope of the captured variable. Now it starts to get cool when you decide to do something interesting like modify captured variables or capture multiple variables. Check out these snippets (for brevity):
Easy:
List
for (int counter = 0; counter < 10; counter++)
{
actions.Add(delegate { Console.WriteLine(counter); });
actions.Add(delegate { counter++; });
}
Interesting:
List
for (int counter = 0; counter < 10; counter++)
{
int capture = counter;
actions.Add(delegate { Console.WriteLine(counter + " " + capture); });
}
For extra credit, comment on the output of each snippet. For extra Extra credit, come up with some fantasy classes for each that implements the desired delegate behavior.