Framework Design Guidelines: Avoiding custom delegates

Continuing in our weekly blog post series that highlights a few of the new additions to the Framework Design Guidelines 2nd edition.. This content is foundimage[5]_thumb[2]_thumb[2]_thumb in the Events and Callbacks section of Chapter 6: Designing for Extensibility. I am impressed by how simple new additions to the BCL can have such a large (and positive) effect on framework design. As these new advances come out, learn them and use them!

DO use the new Func<…>, Action<…>, or Expression<…> instead of custom delegates, when defining APIs with callbacks.

Func<…> and Action<…> represent generic delegates. The following is how .NET Framework defines them:

public delegate void Action()
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)
public delegate TResult Func<TResult>()
public delegate TResult Func<T, TResult>(T arg)
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)

They can be used as follows:

Func<int,int,double> divide = (x,y)=>(double)x/(double)y;
Action<double> write = (d)=>Console.WriteLine(d);
write(divide(2,3));

Expression<…> represents function definitions that can be compiled and subsequently invoked at runtime but can also be serialized and passed to remote processes. Continuing with our example:

Expression<Func<int,int,double>> expression =(x,y)=>(double)x/(double)y;
Func<int,int,double> divide = expression.Compile();
write(divide2(2,3));

Notice how the syntax for constructing an Expression<> object is very similar to the one used to construct a Func<> object; in fact, the only difference is the static type declaration of the variable (Expression<> instead of Func<>).

RICO MARIANI

Most times you’re going to want Func or Action if all that needs to happen is to run some code. You need Expression when the code needs to be analyzed, serialized, or optimized before it is run. Expression is for thinking about code, Func/Action is for running it.

Comments

  • Anonymous
    January 28, 2009
    I think this is good advice although it's worth mentioning that you may not always have access to these delegates. All of the above delegates are defined in .NET 3.5, which rules them out if you're targeting .NET 2.0. Other potentially suitable delegates can also bring in an unwanted dependency or have a misleading name. E.g. if you need a delegate that does not return a value and accepts no parameters for .NET 2.0 you might consider MethodInvoker, but this brings a dependency on Windows Forms. You could also consider ThreadStart, but this implies the delegate will be invoked on a different managed thread. So while I agree with the advice in general, there are still legitimate scenarios where I think a custom delegate will offer greater clarity for an API.

  • Anonymous
    January 29, 2009
    The comment has been removed

  • Anonymous
    January 29, 2009
    Interesting note and it kind of makes sense, but I wish it were a little less dogmatic ("DO use the new Func, Action or Expression instead of custom delegates") and provided more explanation of why that's a good thing. The delegates look reasonable and, now that I know of them I'll probably use them, but, as Lee Campbell points out, custom delegates can be made clearer. So, what's lost in not using the new delegates?

  • Anonymous
    January 29, 2009
    The comment has been removed

  • Anonymous
    January 29, 2009
    Continuing in our weekly blog post series that highlights a few of the new additions to the Framework

  • Anonymous
    February 10, 2009
    It's snowing again. Like every other time in Southern-most NJ (near Philly) if it accumulates more than an inch, I will be astonished. Very unlike where we used to live in New Hampshire, where for 2 years, they have at least weekly snow storms of 8 or

  • Anonymous
    March 26, 2009
    That's really interesting. And I think it is a good advice for beginners.