C# Language The Func, Action and Predicate delegate types


Example

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>.