Frankie wrote:
Thank you Peter... RE:
<<they do really make it a LOT easier to deal with situations where you want
to use local variables (including method parameters) in the code. >>
Would an example of this [what you are talking about] be a situation where
an anonymous method is used in conjunction with the returning of a delegate
that makes use of an anonymous method, like this?:
...
return delegate() {... anonymous method here...}
or this?
....
someDelegateInstance += delegate {... anonymous method here...}
Since you didn't post any of the code inside the anonymous method, I
can't say whether those are an example of what I mean or not. In
particular, if the anonymous method doesn't reference any local
variables, then no...those aren't really examples of what I'm talking about.
If, on the other hand, they do reference local variables then
sure...those could be examples of what I'm talking about, even though
they aren't specifically what I had in mind.
If those do not qualify as examples of what you are talking about, can you
provide a brief example? Thanks!
Maybe Brian's reply has already elaborated this for you. But his
List.Find() example is exactly the sort of situation I had in mind. In
particular, .NET includes a lot of methods that take a predicate
delegate, used as a filter for some iterative process.
Often, you want the method implementing that predicate to be able to
make variable comparisons. That is, in some cases you can hard-code a
constant, but many situations call for passing in a value to use for a
comparison. In those cases, you need a place to put the value where the
method used for the predicate can get at it.
Without anonymous methods, the usual solution is to create a simple
class containing that value and the method. Then you instantiate the
class, initializing the value to the value you want, and creating the
predicate delegate using the method from the class:
class MyPredicateClass
{
int _i;
public MyPredicateClass(int i)
{
_i = i;
}
public bool MyPredicateMethod(int i)
{
return _i == i;
}
}
Then you use it in some method like this:
int MyIndexOf(List<intlist, int i)
{
MyPredicateClass mpc = new MyPredicateClass(i);
return list.FindIndex(mpc.MyPredicateMethod);
}
(Of course, the above is extremely simplistic, and already fully
supported by List<without using predicates...in a real situation, the
predicate method would usually be doing a more complex evaluation. But
for the purposes of illustration, I think the simpler code is better).
Note the simple MyPredicateClass, the only purpose for which is to store
some data used by the predicate method. Using an anonymous method you
could do this much more simply as follows:
int MyIndexOf(List<intlist, int iFind)
{
return list.FindIndex(
delegate(int iObj) { return iObj == iFind; } );
}
The magic here is that the "iFind" local variable is "captured" by the
anonymous method, allowing it to be used by that method when it's used
as a predicate, without having to explicitly store it somewhere.
This sort of advantage is not by any means limited to anonymous methods
used as predicates. It just happens that the predicate scenario is a
fairly common and easily-explain example.
In the simplest cases, this is all you really need to know. You can
start using anonymous methods, making lots of good use of them, with
just the above information. Watch out though...anonymous methods do
carry the potential for some strange complications. :) Read on...
Even if the anonymous method is used asynchronously, variables are still
captured and can live on past the lifetime of the scope where the
anonymous method was declared. For many situations this isn't an issue;
even if the anonymous method is used asynchronously (for example, as the
argument for a call to Control.BeginInvoke(), a reasonably common
asynchronous technique), often the variable being passed is a just a value.
But if it's a reference type, and the object is mutable, then some other
code could change the object after the asynchronous call was made, but
before the anonymous method is actually executed, or the anonymous
method could asynchronously affect other code using the same object (if
it modifies the object). Similarly, local variables that are arguments
passed by reference ("out" or "ref") still act in the same way that they
would in the method to which they were passed, introducing some
potentially difficult synchronization issues.
So, with the added power of anonymous methods comes great responsibility
to use them wisely. But isn't that always the case? :)
Pete