System-Defined Delegates: Func<>
In .NET 3.5 (C# 3.0), there exists a series of generic delegates with the name "Func." The signatures for these delegates are shown in Listing 12.13.
Listing 12.13. Func Delegate Declarations
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)
Since these delegate definitions are generic, it is possible to use them instead of defining a custom delegate. For example, rather than declaring the ComparisonHandler delegate type, code could simply declare ComparisonHandler delegates using Func<int, int, bool>. The last type parameter of Func is always the return type of the delegate. The earlier type parameters correspond in sequence to the type of delegate parameters. In the case of ComparisonHandler, the return is bool (the last type parameter of the Func declaration) and the type arguments int and int correspond with the first and second parameters of ComparisonHandler. In many cases, the inclusion of Func delegates into the .NET 3.5 Framework eliminates the necessity to define delegates with four or fewer parameters that return a value. (You should use System.Action for delegates that have no return and that take no parameters.)
However, you should still declare delegate types when a specific delegate type would simplify coding with the delegate. For example, continuing to use the ComparisonHandler provides a more explicit indication of what the delegate is used for, whereas Func<int, int, bool> provides nothing more than an understanding of the method signature.
Evaluation about whether to declare a delegate is still meaningful and includes considerations such as whether the name of the delegate identifier is sufficient for indicating intent, whether the delegate type name would clarify its use, and whether the use of a .NET 3.5 type will limit the use of the assembly to .NET 3.5 clients unnecessarily.
Note that even though you can use a Func generic delegate in place of an explicitly defined delegate, the types are not compatible. You cannot assign any expression of one delegate type to a variable of another delegate type. For example, you cannot assign a ComparisonHandler variable to a Func<int, int, bool> variable or pass them interchangeably as parameters.