Importance of Anonymous Methods/Delegates

  • Thread starter Thread starter Frankie
  • Start date Start date
F

Frankie

I have just gotten up to speed on what anonymous methods are (syntax,
capabilities, etc), and how they can be used with /called via delegates.

What I am wondering is...

1. Are they only/mostly syntactic sugar (important as that can be)?

2. Are anonymous methods *required* anywhere? That is, are anonymous methods
the only way [or "by far" the easiest way] to accomplish certain tasks in
..NET programming?

Just trying to get a grip on where I might benefit from using anonymous
methods/delegates.

Thanks.
 
Frankie,

1. Yes.

2. No. Wherever anonymous delegates are used, you could certainly create a
method/class which will do the same thing that the anonymous delegate does.
Granted, the fact that anonymous delegates are closures and encapsulate
local variables is not always easily duplicated is difficult to get around
at times, but not impossible.

Generally though, anonymous delegates are an improvement over having to
write full blown methods for simple actions that you need to have performed
in callbacks and events.
 
Nicholas said:
Frankie,

1. Yes.

2. No. Wherever anonymous delegates are used, you could certainly
create a method/class which will do the same thing that the anonymous
delegate does. Granted, the fact that anonymous delegates are closures
and encapsulate local variables is not always easily duplicated is
difficult to get around at times, but not impossible.

Though, IMHO this latter point is what puts them into the category of
"or 'by far' the easiest way", something that the OP did ask about.

So while not strictly "required" in that case, 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. The alternative, creating a
class to specifically contain those values and the method that would
otherwise be the anonymous one, is IMHO much more cumbersome.

Pete
 
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...}

If those do not qualify as examples of what you are talking about, can you
provide a brief example? Thanks!
 
So while not strictly "required" in that case, 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. The alternative, creating a
class to specifically contain those values and the method that would
otherwise be the anonymous one, is IMHO much more cumbersome.

Pete

Furthermore, I find myself more frequently using methods that accept
delegates in C# than I do in VB.NET precisely because it's more
convenient with anonymous methods. I am specifically talking about
methods like List.Find. I'm very much looking forward to lambda
expressions.
 
Frankie said:
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<int> list, 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<int> list, 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
 
Thank you Peter so much! Your example with a predicate delegate not only
illustrates the point very well, but provides a more elegant solution to a
hack I threw together about a year ago with predicate delegates... time to
refactor now that I have a better understanding of anonymous methods.

-F


Peter Duniho said:
Frankie said:
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<int> list, 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<int> list, 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
 
Frankie said:
Thank you Peter so much! Your example with a predicate delegate not only
illustrates the point very well, but provides a more elegant solution to a
hack I threw together about a year ago with predicate delegates... time to
refactor now that I have a better understanding of anonymous methods.

You're welcome...I'm glad you found the information helpful. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top