Lambda and anonymous functions and delegates are all extremely useful and awesome features of C#, but sometimes using them in any way but the simplest fashion can feel like hard work. This is often because C# is a strictly typed language, and so the compiler always needs to be able to resolve the types for your delegates - to determine where they can and can't be used.
So sometimes, when you find that you need to pass around a delegate, you end up needing to write a delegate declaration. And really, even though it is generally a single simple line of code, it can be very annoying. First, because you have to remember the syntax for writing a delegate declaration, and second because you have to find someplace useful to put it (which is doubly annoying - because you were probably using the anonymous function in the first place because you didn't want have to pull it out and put it somewhere specific).
For instance, take a look a tutorial from about a year ago, the tutorial on how to use the lambda operator. In that tutorial, we wrote a method that would take a delegate and fold it across the rest of the arguments to the function. It looked like this:
public int Fold(FoldIntDelegate fid, params int[] list)
{
int result = 1;
foreach (int i in list)
result = fid(result, i);
return result;
}
That first line is the line that I'm complaining about - the line I'd like to get rid of. Well, guess what? You can! There are a whole bunch of basic delegate declaration in the System namespace that cover almost all of the common delegate declaration cases by using generics. For instance, that Fold method could have been written like this:
{
int result = 1;
foreach (int i in list)
result = fid(result, i);
return result;
}
So instead of using the custom FoldIntDelegate from the first block of code, here we are using a generic Func delegate (one that allows you to specify two argument types and a return value type. The declaration for this delegate looks like this:
This delegate declaration will cover any two argument method that has a return value - all you have to do is provide the types for the arguments/return values.
But that's not all - there is a lot more where that came from.
The Funcs
The Funcs are the delegate declaration for delegates that return a value, and were first introduced in .NET 3.5. We have already seen one, the two argument Func. But there are Func declarations for everything from no arguments to 4 arguments:
Func(TResult)Func(T1, TResult)Func(T1, T2, TResult)Func(T1, T2, T3, TResult)Func(T1, T2, T3, T4, TResult)
And here are what their declarations look like:
public delegate TResult Func<T1, TResult>(T1 arg1);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1,
T2 arg2, T3 arg3, T4 arg4);
So if you need more than 4 arguments, you have to make your own declaration. But most of the time, you don't, and so this covers many of the common signatures.
I can hear you now, though - what if I don't want to return a value? Well, don't worry, that is here too:
The Actions
The Actions are the delegate declarations to use when your delegate doesn't return a value. Again, there are Actions for everything from zero (commonly called a thunk) to 4 arguments. And just as a note, the zero argument Action is not actually a generic delegate - cause there is no need for it to be (there are no types to deal with). The single argument Action was introduced in .NET 2, and the rest of them were added in .NET 3.5.
And, for your viewing pleasure, their declarations:
public delegate void Action<T1>(T1 arg1);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1,
T2 arg2, T3 arg3, T4 arg4);
So between those 10 declarations - the Funcs and the Actions - that about covers pretty much every type of delegate you would ever want to pass around. But there are a couple others that you should probably know about.
Specialized Declarations
All four of these specialized delegates have been around since .NET 2, and actually each of them could be replaced by a Func or an Action. But they do serve useful and specific purposes, and generally I think it is a good idea to use one of these (as opposed to the more generic Func/Action) when you are actually doing what these declarations are meant for.
public delegate TOutput Converter<TInput, TOutput>(TInput input);
public delegate bool Predicate<T>(T obj);
public delegate void EventHandler<TEventArgs>(Object sender,
TEventArgs e) where TEventArgs : EventArgs;
First off here we have the Comparison declaration (which could also be seen as a two argument Func). Generally a good one to use if you are writing a delegate that compares two items of the same type. A couple places in the framework expect delegates of type Comparison, most notably the Sort function on List.
Next, we have Converter (which is very similar to a two argument Func). This is used when, as the name might imply, the delegate is converting from the input type to the output type. The place where I use this all the time is also on List, the ConvertAll method.
Following Converter, we have Predicate. This can be looked at as an even more specialized Converter - one that always converts to a boolean. Delegates of type Predicate are expected all over the place, but again, I generally use them when dealing with Lists, like the TrueForAll method. Surprisingly, though, many of the LINQ extension methods don't expect predicates, but instead expect Func<T, bool>.
And then we get to our last special case, the EventHandler declaration. Now this here is a handy beast, for whenever you want an event that doesn't use the standard EventArgs. This is because instead of writing code like this:
{
/*My CustomEventArgs Class Content */
}
public delegate void CustomEventHandler(object sender, CustomEventArgs e);
public event CustomEventHandler SomeEvent;
You can write it like this:
{
/*My CustomEventArgs Class Content */
}
public event EventHandler<CustomEventArgs> SomeEvent;
You might say "bah! It is just a two argument action!." You would be right, except that the EventHandler delegate declaration helps enforce a couple useful things - first, that the event has a sender, and second, that whatever event args class is being passed is derived from EventArgs (that is the where clause at the end of the declaration).
That is it for the built-in delegate declarations! Those signatures should really cover almost every delegate that you would ever want to pass around, and hopefully lowers even further the barrier between you and common use of anonymous functions. If you have any questions about how or when to use any of these, leave them below and I will answer them if I can.
12/14/2008 - 10:55
Really useful feature which I am sure was unknown to most programmers…before this post that is.
06/10/2009 - 15:40
Thanks, great post, I`ve found it very useful
12/06/2009 - 08:30
Pure gold dust!
Must confess, as a 'part-time' (and unpaid..) developer I've found it hard to keep track of the changes to the language, so while this article might be a bit basic to most it has been a great help to me...:)
Many thanks
01/06/2010 - 14:44
Nice, this solution is pretty cool explained, I'm sure a lot of programmers including me, will find this topic very useful.
Thank you!
01/21/2010 - 04:19
Great post man. Cleared up a lot for me.
01/31/2010 - 05:50
nice article. I googled for guilt-in-delegates since I know they exist. But in my project VS tells me "The Type or namespace "Func" could not be found." Do I have to add an assembly reference? Guess no, cause it is in the System assembly. So what is going wrong here? Why can't I use the built-in's?
Thanks in advance.
01/31/2010 - 05:51
add: Yes, I am using .NET 3.5 ;)
01/31/2010 - 06:01
Yes, i missed an assembly: it is included in the System.Core No need for help anymore. Thx.
02/01/2010 - 10:11
Thanks for finding that. It looks like we missed that in the tutorial.
01/26/2011 - 02:17
what are the inbuilt delegation?
04/28/2011 - 13:14
Nice concise list! Thank-you.
One thing has always confused me. Why can't I cast an Action as a delegate? For example,
delegate void likeAction(object param);
void someVoidMethod(object param) {}
void test()
{
Action aMethod = someVoidMethod;
likeAction actionDelegate = aMethod;
}
The compiler always complains about that last line.
09/03/2011 - 13:53
Don't forget ThreadStart. This is the delegate type you pass to the Thread constructor that in turn has the callback reference, before you call the Start method on that instance of Thread.
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.