Func vs. Predicate vs. Expression in C# .Net
Built-in Delegates in C# .Net
In C#, delegates allow you to treat methods as variables, passing them around or assigning them to other methods. While learning about delegates, you may have come across custom delegates, where you define your own delegate types. If you’re unfamiliar with the basics of delegates, I recommend checking out my previous blog post on understanding delegates, where I cover how delegates work and why they’re useful.
In this post, we’ll focus on built-in delegates provided by C#, such asFunc
, Predicate
, Expression
and Action
. These predefined delegates are all used to encapsulate methods or expressions, but they serve different purposes and are used in different contexts.
Here's a breakdown of each:
Func
Func
is a delegate that represents a method that returns a value. You can use it when you need a function that takes one or more inputs and gives you something back. It can take up to 16 parameters and always returns a value of the specified type.
It works for almost anything! but commonly used in LINQ and other functional programming patterns in .NET.
Syntax:
Func<TResult>
: A method with no parameters and returns aTResult
.Func<T1, TResult>
: A method that takes one parameter of typeT1
and returns aTResult
.
Look at the example below that converts an integer to a string :
Func<int, string> func = x => x.ToString();
string result = func(5); // "5"
Note that, Func
takes an integer as input and returns a string equivalent as output.
Predicate
Predicate
is a specialized delegate that represents a method that takes one parameter and always returns a bool
, indicating whether the condition is met. Thus, it wouldn’t be wrong to describe it as a special type of Func
that always returns a true
or false
.
Often used for methods that need to test a condition, like filtering items in a collection. You can use it when you need to check if something is true about a value, like “Is this number even?”
Syntax:
Predicate<T>
: A method that takes a parameter of typeT
and returns abool
.
Here’s an example of Predicate
usage that checks if an integer is even and returns true
or false
.
Predicate<int> isEven = x => x % 2 == 0;
bool isFiveEven = isEven(5); // false
Expression
Expression
is a class used to represent code as data, specifically expressions that can be compiled to executable code or converted to other forms, such as SQL queries in LINQ-to-SQL. I mean, it doesn't just run a method; it can be inspected or even turned into something else.
It builds an “expression tree” that can be looked at or changed before running instead of executing code right away. Then returns that expression tree as a result that can be compiled to a delegate or traversed for analysis.
On that sense, we can say that Expression
is a bit more powerful than the others.
Often used in scenarios where the expression needs to be analyzed or transformed before being executed, like in ORM tools or LINQ providers.
Syntax:
Expression<Func<T, TResult>>
: Represents a lambda expression that can be compiled or interpreted.
Following code snippet represents an expression that checks if an integer is greater than 10 :
Expression<Func<int, bool>> expr = x => x > 10;
// You can compile and run this expression:
Func<int, bool> compiledExpr = expr.Compile();
bool isElevenGreaterThanTen = compiledExpr(11); // true
Comparison & Use Cases
Func
vs Predicate
:
- Use
Func
when you need to return any type of value. - Use
Predicate
when you specifically need to return a boolean value and check a condition. I mean; you need to just checking if something is true or false.
Func
/Predicate
vs Expression
:
- Use
Func
orPredicate
when you need to directly execute a delegate. - Use
Expression
when you need to inspect, modify, or compile the logic before executing it.Expression
is particularly useful in scenarios where the code needs to be translated, like building dynamic queries or converting it to SQL in LINQ.
BONUS: Action
Yeah, there is another built-in delegate called Action
. I couldn’t miss that :)
Action
is similar to Func
, but it does not return any value. It’s used to pass methods that perform an action or some logic but don't need to give anything back (i.e. return void
).
Look at example below, Action
takes a string input but doesn't return anything. It just performs the Console.WriteLine()
operation.
// Prints "Print action called!" to the console
Action<string> print = message => Console.WriteLine(message);
print("Print action called!");
As summary, each of these delegates serves a specific purpose in .NET, and understanding their differences allows you to choose the right one for your particular scenario.
Thank you for reading!
If you found this post helpful, don’t forget to give it a clap and share it with others who might benefit from it.👏👏👏👏👏