Action
doesn't return anything,
Func
does.
Predicate
takes one parameter and returns a boolean.
Table of contents
Action<T1, T2, T3, ...>
Action
has no return value.- The types
T1
,T2
,T3
and so on specify the parameters' types. - There can be between 0 and 16 parameters:
Action
Action<T1>
Action<T1, T2>
Action<T1, T2, T3>
- ...
Action<T1, T2, T3, ..., T16>
Examples:
Action
takes no parameters and returns nothing.Action<int>
takes oneint
parameter and returns nothing.Action<int, bool, int>
takes three parameters of typesint
,bool
andint
, in that order, and returns nothing.
Action lambda1 = () =>
{
Console.WriteLine("lambda1 was called");
// No return value
};
Action<int> lambda2 = (int param1) =>
{
Console.WriteLine($"lambda2 was called with {param1}");
// No return value
};
Action<int, bool, int> lambda3 = (int param1, bool param2, int param3) =>
{
Console.WriteLine($"lambda3 was called with {param1}, {param2} and {param3}");
// No return value
};
Func<T1, T2, T3, ..., TResult>
Func
returns a value of typeTResult
.- The types
T1
,T2
,T3
and so on specify the parameters' types. - There can be between 0 and 16 parameters:
Func<TResult>
Func<T1, TResult>
Func<T1, T2, TResult>
Func<T1, T2, T3, TResult>
- ...
Func<T1, T2, T3, ..., T16, TResult>
TResult
is always in the last position, i.e. the last type always specifies the return value's type.
Examples:
Func<string>
takes no parameters and returns astring
.Func<int, string>
takes oneint
parameter and returns astring
.Func<int, bool, int, string>
takes three parameters of typesint
,bool
andint
, in that order, and returns astring
.
Func<string> lambda1 = () =>
{
return "lambda1 was called";
};
Func<int, string> lambda2 = (int param1) =>
{
return $"lambda2 was called with {param1}";
};
Func<int, bool, int, string> lambda3 = (int param1, bool param2, int param3) =>
{
// `null` return value is ok too
// because strings can be null
if (!param2) return null;
return $"lambda3 was called with {param1}, {param2} and {param3}";
};
Predicate<T>
Predicate
returns a boolean.Predicate
takes one parameter of typeT
.
Examples:
Predicate<int>
takes oneint
parameter and returns a boolean.Predicate<string>
takes onestring
parameter and returns a boolean.
Predicate<int> IsPositive = (int param) =>
{
return param > 0;
};
Predicate<string> StartsWithFoo = (string param) =>
{
return param?.StartsWith("foo") ?? false;
};
Predicate<T>
vs Func<T, bool>
Predicate<T>
is effectively the same as Func<T, bool>
.
They both take a single parameter of type T
and return a boolean.
That said, they are not assignment-compatible. Example from the linked Stack Overflow answer by Daniel Earwicker (slightly modified):
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; // Doesn't work
f = p; // Doesn't work
}
Which one to use,
Predicate<T>
or Func<T, bool>
?
If you can choose,
my hunch is that Func
is better because:
Func
has overloads that take more than one input type, so it's more flexible thanPredicate
.Func<T, bool>
is clear (given that you know howFunc
s work), whereasPredicate
is more niche and makes sense only if you know what a "predicate" is.
On the other hand,
Predicate<T>
is short and descriptive,
so I don't have a strong opinion
which one to prefer.
Further resources
This blog post was inspired by Scott Steffes's YouTube video Generic Delegate Types (Action, Func, Predicate), in C#. There's interesting discussion about the delegate keyword versus lambda syntax in a Reddit thread around the video.
See also these pages in the .NET docs: