Func is a delegate that points to a method that accepts one or more arguments and returns a value. Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value. In other words, you should use Action when your delegate points to a method that returns void.
Predicate is the delegate like Func and Action delegates. It represents a method containing a set of criteria and checks whether the passed parameter meets those criteria. A predicate delegate methods must take one input parameter and return a boolean - true or false.
The Func delegate takes zero, one or more input parameters, and returns a value (with its out parameter). Action takes zero, one or more input parameters, but does not return anything. Predicate is a special kind of Func.
Func<T, TResult> defines a function that accepts one parameter (of type T) and returns an object (of type TResult).
While Predicate
has been introduced at the same time that List<T>
and Array<T>
, in .net 2.0, the different Func
and Action
variants come from .net 3.5.
So those Func
predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about using Func<T>
and Action<T>
the guideline states:
Do use the new LINQ types
Func<>
andExpression<>
instead of custom delegates and predicates
I've wondered this before. I like the Predicate<T>
delegate - it's nice and descriptive. However, you need to consider the overloads of Where
:
Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
That allows you to filter based on the index of the entry as well. That's nice and consistent, whereas:
Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
wouldn't be.
Surely the actual reason for using Func
instead of a specific delegate is that C# treats separately declared delegates as totally different types.
Even though Func<int, bool>
and Predicate<int>
both have identical argument and return types, they are not assignment-compatible. So if every library declared its own delegate type for each delegate pattern, those libraries would not be able to interoperate unless the user inserts "bridging" delegates to perform conversions.
// declare two delegate types, completely identical but different names:
public delegate void ExceptionHandler1(Exception x);
public delegate void ExceptionHandler2(Exception x);
// a method that is compatible with either of them:
public static void MyExceptionHandler(Exception x)
{
Console.WriteLine(x.Message);
}
static void Main(string[] args)
{
// can assign any method having the right pattern
ExceptionHandler1 x1 = MyExceptionHandler;
// and yet cannot assign a delegate with identical declaration!
ExceptionHandler2 x2 = x1; // error at compile time
}
By encouraging everyone to use Func, Microsoft is hoping that this will alleviate the problem of incompatible delegate types. Everyone's delegates will play nicely together, because they will just be matched up based on their parameter/return types.
It doesn't solve all problems, because Func
(and Action
) can't have out
or ref
parameters, but those are less commonly used.
Update: in the comments Svish says:
Still, switching a parameter type from Func to Predicate and back, doesn't seem to make any difference? At least it still compiles without any problems.
Yes, as long as your program only assigns methods to delegates, as in the first line of my Main
function. The compiler silently generates code to new a delegate object that forwards on to the method. So in my Main
function, I could change x1
to be of type ExceptionHandler2
without causing a problem.
However, on the second line I try to assign the first delegate to another delegate. Even thought that 2nd delegate type has exactly the same parameter and return types, the compiler gives error CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.
Maybe this will make it clearer:
public static bool IsNegative(int x)
{
return x < 0;
}
static void Main(string[] args)
{
Predicate<int> p = IsNegative;
Func<int, bool> f = IsNegative;
p = f; // Not allowed
}
My method IsNegative
is a perfectly good thing to assign to the p
and f
variables, as long as I do so directly. But then I can't assign one of those variables to the other.
The advice (in 3.5 and above) is to use the Action<...>
and Func<...>
- for the "why?" - one advantage is that "Predicate<T>
" is only meaningful if you know what "predicate" means - otherwise you need to look at object-browser (etc) to find the signatute.
Conversely Func<T,bool>
follows a standard pattern; I can immediately tell that this is a function that takes a T
and returns a bool
- don't need to understand any terminology - just apply my truth test.
For "predicate" this might have been OK, but I appreciate the attempt to standardise. It also allows a lot of parity with the related methods in that area.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With