Share via


C# : Action, Func<TResult> and Predicate<T> Delegate

Introduction

I am pretty sure you all must have seen these delegates when writing code. IntelliSense shows methods that accept Actions, Func<TResult> and some accept Predicate<T>. So what are these? Let’s find out.

Let’s go by a simple example. I have following “Employee” class and it has a helper method which will return me a list of Employees.

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime Birthday { get; set; }
    public int Age { get; set; }
 
    public static List<Employee> GetEmployeees()
    {
        return new List<Employee>()
        {
            new Employee()
            {
                FirstName = "Jaliya",
                LastName = "Udagedara",
                Birthday =  Convert.ToDateTime("1986-09-11")
            },
            new Employee()
            {
                FirstName = "Gary",
                LastName = "Smith",
                Birthday = Convert.ToDateTime("1988-03-20")
            }
        };
    }
}

In my Main method I am getting the list of type employees into a variable

List<Employee> employees = Employee.GetEmployeees();

Action

Action series of delegates are pointers to methods which take zero, one or more input parameters, and do not return anything.

Let’s consider List<T>.ForEach method, which accepts a Action of type T. For my list of type Employee, it accepts an Action of type Employee.

http://lh5.ggpht.com/-3vXTtC52Opg/UrBztKM4f9I/AAAAAAAAB9g/Qr5XEY1_SuQ/Untitled_thumb3.png?imgmax=800
Action

 So let’s create an Action now. I have the following method which will calculate the age of the employee when the employee is passed in.

static void CalculateAge(Employee emp)
{
    emp.Age = DateTime.Now.Year - emp.Birthday.Year;
}

So I can create an Action, pointing to above method.

Action<Employee> empAction = new Action<Employee>(CalculateAge);

employees.ForEach(empAction); 

foreach (Employee e in employees)
{
   Console.WriteLine(e.Age);
}

This will print me the calculated age for each employee. With the use of Lambda Expressions, I can eliminate writing a separate method for calculating the age and put it straight this way.

employees.ForEach(e => e.Age = DateTime.Now.Year - e.Birthday.Year);

Func<TResult>

Func<TResult> series of delegates are pointers to methods which take zero, one or more input parameters, and return a value of the type specified by the TResult parameter.

For this, let’s consider Enumerable.First<TSource> method, which has an overloading method which accepts a Func.

http://lh6.ggpht.com/-wfOQ5Jn1qVA/UrBzwreXqZI/AAAAAAAAB9w/K0yCfKTsx0I/Untitled_thumb7.png?imgmax=800
Func

In my scenario, this particular method accepts Func which accepts an Employee and returns a bool value. For this, let’s create a method which I am going to point my Func to. Following method accepts an employee and checks whether his/her FirstName is equal to “Jaliya” and returns true or false.

static bool NameIsEqual(Employee emp)
{
    return emp.FirstName == "Jaliya";
}

Now I can create a Func and get the first employee which satisfies the condition on Func.

Func<Employee, bool> myFunc = new Func<Employee, bool>(NameIsEqual);
Console.WriteLine(employees.First(myFunc).FirstName);

Again with the use of Lambda Expressions, I can make my code simple.

Console.WriteLine(employees.First(e => e.FirstName == "Jaliya").FirstName);

Predicate<T>

Predicate<T> represents a method that defines a set of criteria and determines whether the specified object meets those criteria.

For this, let’s consider List<T>.Find Method which accepts a Predicate.

http://lh5.ggpht.com/-6DjG6XV78cM/UrBzyH6w8mI/AAAAAAAAB-A/OTIwJYzpYrE/Untitled_thumb10.png?imgmax=800
Predicate

In here it’s a Predicate of type Employee. So let’s create a method which accepts a Employee and check whether he/she is born in “1986”. If yes, it will return true or else false.

static bool BornInNinteenEightySix(Employee emp)
{
    return emp.Birthday.Year == 1986;
}

Now I am creating a Predicate pointing to above method.

Predicate<Employee> predicate = new Predicate<Employee>(BornInNinteenEightySix); 

Console.WriteLine(employees.Find(predicate).FirstName);

Again with the use of Lambda Expressions, I can simplify the code.

Console.WriteLine(employees.Find(e => e.Birthday.Year == 1986).FirstName);

Func Vs. Predicate<T>

Now you must be wondering what is the difference between Func and Predicate. Basically, those are the same, but there is a one significant difference.

A Predicate can only be used point to methods which will return bool. If the pointing method returning something other than a bool value, you can��t use predict. For that, you can use Func. Let’s take a look at following method.

static string MyMethod(int i)
{
    return "You entered: " + i;
}

The method accepts an integer value and returns a string. I can create the following Func and use it to call the above method.

Func<int, string> myFunc = new Func<int, string>(MyMethod); 

Console.WriteLine(myFunc(3));

This will compile and print the desired output. But if you try to create a Predicate for this, you can’t.

Download sample

I am uploading the sample to MSDN Code Gallery. Do play around!.

   Download Sample

Happy Coding.