[...]Briefly, an anonymous method is exactly that: a method without a name.
lblErrorCode.Invoke(new MethodInvoker(delegate { lblErrorCode.Text =
Enum.GetName(typeof(ErrorCodes), Int32.Parse(msg)); }));
This works, but I don't have a clue why. Can someone explain what's
going on here in simple terms? Thanks, Tom
When you use the "delegate" keyword to declare an anonymous method, all
you're doing is writing a method the same as you would anywhere else,
except that it doesn't have a name, and so you have to use it right away
rather than being able to refer to it elsewhere. (And I mean that only in
the static, "we're writing the code now" sense of "right away"...obviously
at run-time, as long as you've created a delegate variable that refers to
the anonymous method, that can be used any time, any place you like).
You can even declare your anonymous method with parameters, by putting
them after the "delegate" keyword. For example, suppose you want to
declare an event handler anonymously. You could do this:
EventHandler handler = delegate(object sender, EventArgs e) { // your
code here };
In the method, you can refer to "sender" and "e" just as you could in a
named method.
And just as a named method has access to members that are in any class
that contains the named method, the anonymous method has access to any
containing member's member. The thing that makes it a little odd is that
whereas a named method is contained only by one or more classes, an
anonymous method can be contained by a named method. This means it _also_
has access to anything in the named method that's in the same scope as the
anonymous method.
That's where the use of the "msg" parameter in your example comes in. The
anonymous method has access to it, because "msg" is in scope in the same
place that the anonymous method is declared.
As far as all that goes, I think it's really pretty simple. As I said,
it's basically the same as declaring any method anywhere.
The one sort of odd part is that when an anonymous method uses a parameter
or local variable like this, it gets "captured". To understand why,
consider that the anonymous method can be executed at any time, not just
while the containing method is still executing. When a method returns,
its parameters and variables no longer exist and so without capturing, an
anonymous method that used them would be in trouble.
C# gets around this by moving any parameters or local variables into a
hidden class accessible by the anonymous method, so that they will stay
alive as long as the anonymous method does.
Now, as if that weren't potentially confusing enough, it's important to
understand that these captured variables are actually created according to
the scope in which they are declared. This:
int i;
List<Actionactions = new List<Action>();
for (i = 0; i < 5; i++)
{
actions.Add(delegate { Console.WriteLine(i); });
}
foreach (Action action in actions)
{
action();
}
Produces completely different output than this:
int i;
List<Actionactions = new List<Action>();
for (i = 0; i < 5; i++)
{
int iT = i;
actions.Add(delegate { Console.WriteLine(iT); });
}
foreach (Action action in actions)
{
action();
}
The first outputs:
5
5
5
5
5
The second outputs:
0
1
2
3
4
This is because in the first case, each of the five anonymous methods
created are all sharing the same variable, "i". By the time the methods
get to execute, that variable has been set to the value "5". In the
second case, each of the five anonymous methods created get a different
variable, "iT", the value of which is set once to the value of "i" at the
time that the "iT" variable is created and never changed. So when the
anonymous methods get to execute, they each use the individual "iT"
variable created just for it.
This "capturing" behavior can be a bit confusing at first, but it turns
out to be very convenient in managing the data used by an anonymous
method. Of course, if you're not careful, it can wind up biting you; not
only do you have the issue demonstrated above in which the variable value
may change before the anonymous method gets to execute, if you're using
the anonymous method for implementing threading behavior, you could run
into thread synchronization problems.
Of course, by being careful to provide each anonymous method with its own
copy of the value, it's actually a nice way to _deal with_ thread
synchronization problems. So, it's a dual-edged sword, useful for good as
well as evil. :)
Pete