Func vs. Action vs. Predicate
Solution 1
The difference between Func
and Action
is simply whether you want the delegate to return a value (use Func
) or not (use Action
).
Func
is probably most commonly used in LINQ - for example in projections:
list.Select(x => x.SomeProperty)
or filtering:
list.Where(x => x.SomeValue == someOtherValue)
or key selection:
list.Join(otherList, x => x.FirstKey, y => y.SecondKey, ...)
Action
is more commonly used for things like List<T>.ForEach
: execute the given action for each item in the list. I use this less often than Func
, although I do sometimes use the parameterless version for things like Control.BeginInvoke
and Dispatcher.BeginInvoke
.
Predicate
is just a special cased Func<T, bool>
really, introduced before all of the Func
and most of the Action
delegates came along. I suspect that if we'd already had Func
and Action
in their various guises, Predicate
wouldn't have been introduced... although it does impart a certain meaning to the use of the delegate, whereas Func
and Action
are used for widely disparate purposes.
Predicate
is mostly used in List<T>
for methods like FindAll
and RemoveAll
.
Solution 2
Action is a delegate (pointer) to a method, that takes zero, one or more input parameters, but does not return anything.
Func is a delegate (pointer) to a method, that takes zero, one or more input parameters, and returns a value (or reference).
Predicate is a special kind of Func often used for comparisons (takes a generic parameter and returns bool).
Though widely used with Linq, Action and Func are concepts logically independent of Linq. C++ already contained the basic concept in form of typed function pointers.
Here is a small example for Action and Func without using Linq:
class Program
{
static void Main(string[] args)
{
Action<int> myAction = new Action<int>(DoSomething);
myAction(123); // Prints out "123"
// can be also called as myAction.Invoke(123);
Func<int, double> myFunc = new Func<int, double>(CalculateSomething);
Console.WriteLine(myFunc(5)); // Prints out "2.5"
}
static void DoSomething(int i)
{
Console.WriteLine(i);
}
static double CalculateSomething(int i)
{
return (double)i/2;
}
}
Solution 3
Func - When you want a delegate for a function that may or may not take parameters and returns a value. The most common example would be Select from LINQ:
var result = someCollection.Select( x => new { x.Name, x.Address });
Action - When you want a delegate for a function that may or may not take parameters and does not return a value. I use these often for anonymous event handlers:
button1.Click += (sender, e) => { /* Do Some Work */ }
Predicate - When you want a specialized version of a Func that evaluates a value against a set of criteria and returns a boolean result (true for a match, false otherwise). Again, these are used in LINQ quite frequently for things like Where:
var filteredResults =
someCollection.Where(x => x.someCriteriaHolder == someCriteria);
I just double checked and it turns out that LINQ doesn't use Predicates. Not sure why they made that decision...but theoretically it is still a situation where a Predicate would fit.
InfoLearner
Updated on July 08, 2022Comments
-
InfoLearner almost 2 years
With real examples and their use, can someone please help me understand:
- When do we need a
Func<T, ..>
delegate? - When do we need an
Action<T>
delegate? - When do we need a
Predicate<T>
delegate?
- When do we need a
-
Tim_K over 13 yearsI rather like seeing
Predicate
in a function signature. It illustrates that the passed method makes a decision rather than just returns a success code or a different sort ofbool
. -
CodesInChaos over 13 yearsIs there any design guideline on whether to prefer
Predicate<T>
orFunc<T,bool>
? I like the expressiveness ofPredicate
, but I've seen recommendations forFunc
too. -
Jon Skeet over 13 years@Ron: Yes, that's pretty much what my penultimate paragraph was about.
-
Jon Skeet over 13 years@CodeInChaos: Not that I've seen. LINQ uses
Func
throughout, but that's probably for consistency given that many method accepting aFunc<T,bool>
as a predicate also have an overload taking aFunc<T,int,bool>
for an indexed predicate. -
Federico Motta over 12 yearsI know this is old, but Predicate was not used by LINQ because it predates the Func and Action that we know today, and the latter two can be used to achieve the exact same result in a much better way.
-
Juvil over 11 yearsi kind'a like how simple you have explained it. func - returns action - performs (method)
-
Sam almost 11 years@gparent, why is it better? I think the readability is better when meaningfully-named delegates are used instead of
Func
orAction
. -
Federico Motta almost 11 yearsIt depends how you use delegates, but sometimes the name isn't so important and having to create functions and variables just for one use to me decreases readability.
-
Martin over 10 yearsPredicate is a delegate that takes generic parameters and returns bool
-
gimbar over 10 yearsWho tought it would be useful to have 3 different name for the same thing? It's just a function pointer!
-
romar over 10 yearsNice example! Note that you can also invoke myAction by simply calling it:
myAction(123);
. You don't need to use.Invoke()
-
Slipp D. Thompson over 9 years@JonSkeet, Yes, but your second-to-last paragraph reads like a history of how things went down, hiding that intent in the middle of it and making it look like an off-comment. @Ron's comment is clear in that it's a desirable effect (not just a byproduct of software evolution), and makes the point that an intentional choice may be made to use
Predicate
s in some use-cases andFunc<…,bool>
s in others to convey meaning. Coincidentally, one could say that the difference between your penultimate paragraph and @Ron's comment is like the difference between usingFunc<T,bool>
andPredicate<T>
. -
ZeRemz about 9 yearsFor what it's worth, in C++ the notion of predicate also means that the function is assumed to be a "pure function", i.e. it should always produce the same result if given the same input, while simple functions-producing-bools do not give such a guarantee. Of course, this is not enforced by the compiler or anything, but explicitly stating that a function parameter is a "predicate" helps documenting this sort of assumption (which can be rather important in some contexts, e.g. for multithreading).
-
Mark Hurd almost 9 yearsNote that Linq (or really overload resolution of both C# and VB) will allow a
Func<T,bool>
where it needs aPredicate<T>
but not vice versa: "cannot convert from 'System.Predicate<int>' to 'System.Func<int, bool>'". -
Mark Hurd almost 9 yearsThis means that if you create a
Where<T>(this s, Predicate p)
extension method for the handful of cases where you already have aPredicate
to use in aWhere
clause, suddenly all yourWhere
clauses match this new extension method (including the one now recursively used internally expecting it to continue to refer to the existingWhere
extension method :-( ). -
Jon Skeet almost 9 years@MarkHurd: I'd have to see the exact situation to understand why overload resolution is behaving in that way. Note that there's a big difference between a lambda expression which can be converted to either a
Func<T, bool>
or aPredicate<T>
, and a reference to an existingPredicate<T>
. To call the original extension method, just call it as a static method:Enumerable.Where(...)
-
Mark Hurd almost 9 yearsPart of what I noticed is specific to VB.NET: as far as I can tell there's no equivalent in C# for
Dim IsEven = Function(x As Integer) ((x And 1) = 0)
. The equivalentvar IsEven = (int x) => ((x & 1) == 0);
complains: "Cannot assign lambda expression to an implicitly-typed local variable". -
Jon Skeet almost 9 years@MarkHurd: It looks like VB creates a new delegate type for situations like that.
-
Mark Hurd almost 9 yearsAnd it means
queryable.Where(IsEven)
is onlyIEnumerable
using the Linq-provided.Where
extensions, but when I provide my ownPredicate
based ones (one forIEnumerable
and one forIQueryable
) it isIQueryable
. -
A.B. about 6 yearsand just for completeness if you want to use Func which takes no parameters but returns value (or reference) you should write something like this Func<double> myFoo = new Func<double>(foo); and foo definition could be static double foo(){return 1.0;}
-
MarredCheese about 5 years@Martin Predicate only takes one parameter.