Click here to Skip to main content
14,028,233 members
Click here to Skip to main content
Add your own
alternative version

Stats

33.8K views
54 bookmarked
Posted 8 Nov 2014
Licenced CPOL

Delegates (Delegate, Func, Predicate, Action and Lambda)

, 8 Nov 2014
Rate this:
Please Sign up or sign in to vote.
A detailed description for Delegate, Func, Predicate, Action and Lambda Expression.

Introduction

In this article I am going to describe some confusing terms including Func, Action, Predicate, lambda expression and delegate and their differences. Although the introduction of generics and lambda expressions added a bit to the complexity of these terms, they are all the same, Delegates.

This helps you to have a better understanding of these terms and could possibly solve complex interactions between objects and collections.

Background

Delegate has existed in the programming world since a long time ago, however throughout the time many forms of delegates have been added to .Net for the purpose of creating more ways to solve problems.

Let's start with a simple definition of delegates. A delegate is a reference to a piece of code that does something!, exactly like a method. It has arguments as input and results as output.

delegate(int x) {

    return x == 0;
}

If we replace the delegate keyword with 

public bool FunctionName

then it would become

public bool FunctionName(int x){
    return x == 0;
}

so basically in one form it could be a function without a name and more technically an anonymous function. A delegate can also have a name like below and it refers to a method with the same signature.

public bool delegate Name(int x);

and then this could be associated with an event so that other objects can subscribe to it and be notified whenever the event is fired (which is out of scope for this article).

Now that we know what a delegate is, let's use it somewhere exciting such as LINQ and collections. Say we have a collection like this:

var collection = new List<int>();
collection.Add(1);
collection.Add(2);
collection.Add(3);

If we want to filter the elements of this collection, we normally write something like:

collection.Where(x => x == 2);

I will get back to lambda expressions and explain them as part of this article.

Delegate

Now what if I want to describe the condition inside parenthesis with a delegate. Remember a delegate is supposed to reference to a piece of code that does something so basically like a method. So why not comparing some elements and filter them for us, like the lambda expression that I talked about. So what if I write something like:

delegate(int item)
{
    if(item == 2)
    {
        return true;
    }
    return false;
}

and subsequently:

collection.Where(delegate(int item)
            {
                if (item == 2)
                {
                    return true;
                }
                return false;
            });

How was that? So simply this was a delegate which was taking an integer as an input and was returning a boolean as output.

Func

Another form of a delegate is Func. Func could have any number and type of input arguments and could return any type of output, exactly like a delegate. The signature is something like:

Func<int, bool> condition = delegate(int item)
{
    if(item == 2)
    {
        return true;
    }
    return false;
};

Because Func could return any type, we need to mention the return type in the signature (in this case the bool, which is literrally the last argument in the generic definition.

Func<int, bool> condition = deleg...

And I can write:

var result = collection.Where(condition);

Predicate

If a Func only returns a bool, that would have another name called a Predicate, just to confuse us a bit more. So a predicate is a delegate that always returns a boolean with any number and type of inputs. Therefore:

Predicate<int> predicate = delegate(int item)
{
    if(item == 2)
    {
        return true;
    }
    return false;
};

However we need to convert this predicate to a Func if we want to use it like before:

Func<int, bool> condition = new Func<int, bool>(predicate);
collection.Where(condition);

But there are situations that we could use a predicate directly:

collection.Find(predicate);

Best Practice: Use Func, Lambda Expressions and Delegates instead of Predicates.

Action

Now what if my Func didn't return any value, what would be that called then? Yes! an Action. So basically an Action is a delegate that does something without any return value. Something like:

Action<int> action = delegate(int item)
{
    item += 2;
}

Can I use this action with the previous example of filtering? Not really, because the argument to the Where method should return a boolean to evaluate whether that item should be included in the result or not, right? So Where can I use an Action?

The answer is whenever I wanted to do an operation without any return value. like:

collection.ForEach(action);

So this will run for every item in the collection and adds 2 to each item. However note that although this action is run for each item in the collection, in this case the change is not applied because we are modifying a collection using a LINQ for each loop which is not allowed. But it was a Reference type, properties of that type could be changed in a for each loop, like the samples below.

Lambda Expression

Now I'd like to define another synonym for a delegate, a Lambda Expression. A lambda expression can be in the form of a Func or an Action, and therefor inherently it's a delegate. 

So the replacement for the Where argument could be:

Predicate<int> condition = (int x) => x == 2;
Func<int, bool> condition = (int x) => x == 2;

and for the ForEach method I can write:

Action<int> action = (int item) => item += 2;

And that's it. We are there, with all the confusion gone. I have written some samples below for each of these terms in a more complicated fashion. Hope it helps.

Samples

public class Customer
{
    public string Name { get; set; }
    public string Telephone { get; set; }
}
var customers = new List<Customers>();

customers.Add(new Customer() {
    Name = "cust A",
    Telephone = "123"
});
​customers.Add(new Customer() {
    Name = "cust B",
    Telephone = "456"
});
​customers.Add(new Customer() {
    Name = "cust C",
    Telephone = "789"
});

1. Delegate 

customers.Where(delegate(Customer cust) {
    return cust.Name == "cust B";
});

2. Func

Func<Customer, bool> filter = delegate(Customer cust){

    return cust.Name == "cust B";
};

customers.Where(filter);

3. Predicate

Predicate<Customer> filter = delegate(Customer cust){

    return cust.Name == "cust B";
};

customers.Find(filter);

4. Lambda

Func<Customer, bool> filter = (Customer cust) => cust.Name == "cust B";

customers.Where(filter);

5. Action

We can't use Actions here because it doesn't return any value let alone bool.

Now lets play with ForEach method, instead of filtering data:

1. Delegate

customers.ForEach(delegate(Customer cust){
    cust.Name = "cust B name Modified !!!";
});

2. Func

We can't use Func here, as Func has to always return something.

3. Predicate

We can't use predicate here as well, as it always has to return boolean.

4. Lambda

customers.ForEach(cust => cust.Name = "cust B Modified !!!");

5. Action

Action<Customer> filter = (Customer cust) => cust.Name = "cust B Modified !!!";

customers.ForEach(filter);

*) Now a key question! why the following code snippet has a compilation error:

var simpleDelegate = delegate(int x) {

    return x == 0;
};

The answer is, because as you saw, there are different structures (predicate, func, delegate) that could be associated to this delegate, and the compiler doesn't know which one to pick J.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mahdi K.
Technical Lead
Australia Australia
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
QuestionLike others have said Pin
leon de boer21-Oct-16 8:20
memberleon de boer21-Oct-16 8:20 
GeneralMy vote of 5 Pin
Member 292436726-Jun-15 14:33
memberMember 292436726-Jun-15 14:33 
GeneralWell defined and explained. Pin
Narasimhan Jayachandran31-Dec-14 5:58
memberNarasimhan Jayachandran31-Dec-14 5:58 
GeneralMy vote of 1 Pin
s2bert1-Dec-14 23:42
members2bert1-Dec-14 23:42 
GeneralRe: My vote of 1 Pin
KarstenK12-Dec-14 4:28
mveKarstenK12-Dec-14 4:28 
GeneralRe: My vote of 1 Pin
s2bert12-Dec-14 13:43
members2bert12-Dec-14 13:43 
GeneralRe: My vote of 1 Pin
Mahdi K.12-Dec-14 13:52
memberMahdi K.12-Dec-14 13:52 
QuestionDocs are boring Pin
Thornik11-Nov-14 7:43
memberThornik11-Nov-14 7:43 
AnswerRe: Docs are boring Pin
Mahdi K.11-Nov-14 9:35
memberMahdi K.11-Nov-14 9:35 
GeneralRe: Docs are boring Pin
Thornik12-Nov-14 3:43
memberThornik12-Nov-14 3:43 
GeneralMy vote of 2 Pin
s2bert11-Nov-14 4:06
members2bert11-Nov-14 4:06 
GeneralRe: My vote of 2 Pin
Mahdi K.1-Dec-14 18:12
memberMahdi K.1-Dec-14 18:12 
GeneralSuper Pin
Valentino_Lokesh10-Nov-14 7:22
memberValentino_Lokesh10-Nov-14 7:22 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun9-Nov-14 21:40
memberHumayun Kabir Mamun9-Nov-14 21:40 
QuestionIs it true that a lambda expression is inherently a delegate? Pin
George Swan9-Nov-14 21:14
memberGeorge Swan9-Nov-14 21:14 
AnswerRe: Is it true that a lambda expression is inherently a delegate? Pin
s2bert10-Nov-14 6:02
members2bert10-Nov-14 6:02 
GeneralRe: Is it true that a lambda expression is inherently a delegate? Pin
Mahdi K.10-Nov-14 16:38
memberMahdi K.10-Nov-14 16:38 
GeneralRe: Is it true that a lambda expression is inherently a delegate? Pin
s2bert10-Nov-14 23:04
members2bert10-Nov-14 23:04 
GeneralRe: Is it true that a lambda expression is inherently a delegate? Pin
Mahdi K.10-Nov-14 23:19
memberMahdi K.10-Nov-14 23:19 
GeneralRe: Is it true that a lambda expression is inherently a delegate? Pin
s2bert11-Nov-14 3:19
members2bert11-Nov-14 3:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04 | 2.8.190419.4 | Last Updated 9 Nov 2014
Article Copyright 2014 by Mahdi K.
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid