Delegates: Predicate vs. Action vs. Func

C#DelegatesPredicateFunc

C# Problem Overview


Can someone provide a good explanation (hopefully with examples) of these 3 most important delegates:

  • Predicate
  • Action
  • Func

C# Solutions


Solution 1 - C#

  • Predicate: essentially Func<T, bool>; asks the question "does the specified argument satisfy the condition represented by the delegate?" Used in things like List.FindAll.

  • Action: Perform an action given the arguments. Very general purpose. Not used much in LINQ as it implies side-effects, basically.

  • Func: Used extensively in LINQ, usually to transform the argument, e.g. by projecting a complex structure to one property.

Other important delegates:

  • EventHandler/EventHandler<T>: Used all over WinForms

  • Comparison<T>: Like IComparer<T> but in delegate form.

Solution 2 - C#

Action, Func and Predicate all belong to the delegate family.

Action : Action can take n input parameters but it returns void.

Func : Func can take n input parameters but it will always return the result of the provided type. Func<T1,T2,T3,TResult>, here T1,T2,T3 are input parameters and TResult is the output of it.

Predicate : Predicate is also a form of Func but it will always return bool. In simple words it is wrapper of Func<T,bool>.

Solution 3 - C#

In addition to Jon's answer, there is also

  • Converter<TInput, TOutput>: It's essentially Func<TInput, TOutput>, but with semantics. Used by List.ConvertAll and Array.ConvertAll, but personally haven't seen it anywhere else.

Solution 4 - C#

A simple example about the arguments and what retutn each type

This Func take two int arguments and return an int.Func always has return type

 Func<int, int, int> sum = (a, b) => a + b;
 Console.WriteLine(sum(3, 5));//Print 8

In this case func doesn't have arguments but return a string

Func<string> print = () => "Hello world";
Console.WriteLine(print());//Print Hello world

This Action take two int arguments and return void

Action<int, int> displayInput = (x, y) => Console.WriteLine("First number is :" + x + " , Second number is "+ y);
displayInput(4, 6); //Print First number is :4 , Second number is :6

This Predicate take one argument and always return bool.Generally Predicates always return bool.

Predicate<int> isPositive = (x) => x > 0;
Console.WriteLine(isPositive(5));//Print True

Solution 5 - C#

MethodInvoker is one which WinForms developers may use; it accepts no arguments and returns no results. It predates Action, and is still often used when invoking onto the UI thread since BeginInvoke() et al accept an untyped Delegate; although Action will do just as well.

myForm.BeginInvoke((MethodInvoker)delegate
{
  MessageBox.Show("Hello, world...");
});

I'd also be aware of ThreadStart and ParameterizedThreadStart; again most people will substitute an Action these days.

Solution 6 - C#

Predicate, Func and Action are inbuilt delegate instances of .NET. Each of these delegate instances could refer or point to user methods with specific signature.

Action delegate - Action delegate instances could point to methods that take arguments and returns void.

Func delegate - Func delegate instance could point to method(s) that take variable number of arguments and return some type.

Predicate - Predicates are similar to func delegate instances and they could point to methods that take variable number of arguments and return a bool type.

Solution 7 - C#

Action and Func with lambda:

person p = new person();
Action<int, int> mydel = p.add;       /*(int a, int b) => { Console.WriteLine(a + b); };*/
Func<string, string> mydel1 = p.conc; /*(string s) => { return "hello" + s; };*/
mydel(2, 3);
string s1=  mydel1(" Akhil");
Console.WriteLine(s1);
Console.ReadLine();

Solution 8 - C#

Func is more LINQ friendly, can be passed in as a parameter. (point-free)

Predicate cannot, has to be wrapped again.

Predicate<int> IsPositivePred =	i => i > 0;
Func<int,bool> IsPositiveFunc =	i => i > 0;

new []{2,-4}.Where(i=>IsPositivePred(i)); //Wrap again

new []{2,-4}.Where(IsPositivePred);  //Compile Error
new []{2,-4}.Where(IsPositiveFunc);  //Func as Parameter

Solution 9 - C#

Action

Documentation: > Encapsulates a method that has no parameters and does not return a value.

Functions passed using the Action type must return void, and can accept from 0 to 16 parameters.
Action is commonly used when you want a function that can use each element in a container for something, or as callbacks.

public void DoSomething(List<string> lines, Action<string> action)
{
    foreach (string str in lines)
    {
        action(str);
    }
}

Func

Documentation: > Encapsulates a method that has no parameters and returns a value of the type specified by the TResult parameter.

Functions passed using the Func type accept from 0 to 16 parameters, and return any type that isn't void.
Func is commonly used when you want a function that can modify or perform some kind of operation on each element in a container.

//                                                 Parameter Types
//                                                     ▼▼▼  ▼▼▼
public List<int> DoMath(List<(int, int)> numbers, Func<int, int, int> operation)
//                                                               ▲▲▲
//                                                           Return Type
{
    List<int> results = new();
    foreach (var (left, right) in numbers)
    {
        out.Add(operation(left, right));
    }
    return out;
}

Predicate

Documentation: > Represents the method that defines a set of criteria and determines whether the specified object meets those criteria.

Functions passed with the Predicate type must return a bool, and must accept exactly 1 parameter.

An example of functions that accept Predicates are LINQ functions like All & Any, which return true if the supplied predicate returns true for all/any of the elements in a list.

public void Example(string str)
{
    // The char.IsLetter() function can be used as a predicate
    //   because it takes 1 char as a parameter, and returns a bool.
    //          ▼▼▼▼▼▼▼▼▼▼▼▼▼
    if (str.All(char.IsLetter))
    {
        Console.WriteLine("All characters in the string are letters.");
    }
}

Comparison

Type Return Type Min Parameters Max Parameters
Action void 0 16
Func Any type that isn't void 0 16
Predicate bool 1 1

The only differences between Action, Func, and Predicate are the types that they return & accept as parameters; they are all delegates and as such they all represent a function passed as a parameter.

You can make your own delegate types in 1 line of code, and use them in the same way as the premade ones.

//         Accepts functions that return a decimal type, and...
//              ▼▼▼▼▼▼▼
public delegate decimal Operation(decimal left, decimal right);
//                                ▲▲▲▲▲▲▲       ▲▲▲▲▲▲▲
//                    ...take 2 parameters, both of type decimal.

You can read more about delegates here:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSashaView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Rahul GargView Answer on Stackoverflow
Solution 3 - C#G-WizView Answer on Stackoverflow
Solution 4 - C#user9989070View Answer on Stackoverflow
Solution 5 - C#El ZorkoView Answer on Stackoverflow
Solution 6 - C#IntelligentBinaryView Answer on Stackoverflow
Solution 7 - C#user7917367View Answer on Stackoverflow
Solution 8 - C#Rm558View Answer on Stackoverflow
Solution 9 - C#jocolleyView Answer on Stackoverflow