The System namespace contains Func<..., TResult>
delegate types with between 0 and 15 generic parameters, returning type TResult
.
private void UseFunc(Func<string> func)
{
string output = func(); // Func with a single generic type parameter returns that type
Console.WriteLine(output);
}
private void UseFunc(Func<int, int, string> func)
{
string output = func(4, 2); // Func with multiple generic type parameters takes all but the first as parameters of that type
Console.WriteLine(output);
}
The System namespace also contains Action<...>
delegate types with different number of generic parameters (from 0 to 16). It is similar to Func<T1, .., Tn>
, but it always returns void
.
private void UseAction(Action action)
{
action(); // The non-generic Action has no parameters
}
private void UseAction(Action<int, string> action)
{
action(4, "two"); // The generic action is invoked with parameters matching its type arguments
}
Predicate<T>
is also a form of Func
but it will always return bool
. A predicate is a way of specifying a custom criteria. Depending on the value of the input and the logic defined within the predicate, it will return either true
or false
. Predicate<T>
therefore behaves in the same way as Func<T, bool>
and both can be initialized and used in the same way.
Predicate<string> predicate = s => s.StartsWith("a");
Func<string, bool> func = s => s.StartsWith("a");
// Both of these return true
var predicateReturnsTrue = predicate("abc");
var funcReturnsTrue = func("abc");
// Both of these return false
var predicateReturnsFalse = predicate("xyz");
var funcReturnsFalse = func("xyz");
The choice of whether to use Predicate<T>
or Func<T, bool>
is really a matter of opinion. Predicate<T>
is arguably more expressive of the author's intent, while Func<T, bool>
is likely to be familiar to a greater proportion of C# developers.
In addition to that, there are some cases where only one of the options is available, especially when interacting with another API. For example List<T>
and Array<T>
generally take Predicate<T>
for their methods, while most LINQ extensions only accept Func<T, bool>
.