Blog of Petar Vucetin, containing my thoughts, comments and questions. RSS Feed TwitterDiigoFacebookFriendfeed


Cool Delegates

I know I am going to sound like a total geek but delegates are cool! They are lofty, mysterious and fleeting. They do things for you with out complaint. Ok, enough of the prose. Let see what we got in the .Net framework you might find useful.

These delegates are generalization (abstractions?) over some common method signatures and you might find them very handy.

The Action delegate

The Action delegate encapsulates a method that has no return value and it accepts zero or up to four parameters. The signature of this delegate, found in the System namespace, is Action - no parameters; Action(T) - single parameter; Action(T1, T2), Action(T1,T2,T3), Action(T1, T2, T3, T4). This delegate is located in the System.Core assembly which comes in 3.5 version of the .Net framework.

image

In the most common scenario, you use this delegate to perform an action over list of elements.

class Program
{
    static void Main(string[] args)
    {
        var list = new [] {"a", "b"};

        Array.ForEach(list, Console.WriteLine);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

The first parameter of the ForEach method is the array of type T while the second parameter is the Action which takes in T as parameter. From the above example Console.WriteLine fits that bill for the second parameter (no return value and takes single input parameter).

image
 
 
Because we have specified the string array as a first parameter, Visual Studio has figured out that we need an action with single parameter of string type.
image
 
Here is the expanded version explicitly declaring the action and assigning it to the method that accepts single parameter.
class Program
{
    static void Main(string[] args)
    {
        var list = new [] {"a", "b"};

        Action<string> action = Console.WriteLine;

        Array.ForEach(list, action);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

Here is my method that accepts single string parameter and returns no value. I have assigned the action to my PrintToConsole method instead of Console.WriteLine

class Program
{
    static void Main(string[] args)
    {
        var list = new [] {"a", "b"};

        Action<string> action = PrintToConsole;

        Array.ForEach(list, action);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }

    private static void PrintToConsole(string message)
    {
        Console.WriteLine(message);
    }
}

In the next scenario I have array of actions that will be applied to array of strings.

class Program
    {
        static void Main(string[] args)
        {
            var list = new [] {"a", "b"};

            var actions = new Action<string>[] {Console.WriteLine, PrintToConsole};

            Array.ForEach(actions, a =>  Array.ForEach(list, a));

            Console.WriteLine("Done.");
            Console.ReadLine();
        }

        private static void PrintToConsole(string message)
        {
            Console.WriteLine(message);
        }
    }
 
Useful? I think so.
 

The Predicate

Predicate(T) is another very useful delegate. This is any method that return bool and accepts a single parameter. This delegate is located in the mscorlib version 2.0 assembly.

You pass it instance of a type T and you can test if the instance of T meets some criteria by returning true if it does or false if it does not. This is the signature of the predicate: public delegate bool Predicate<T>( T obj )

image

Here is the simplest of examples:

class Program
{
    static void Main(string[] args)
    {
        //Predicate expressed as lambda
        Predicate<string> p = testSubject => true;
        
        // Predicate expressed as anonymous method
        //Predicate<string> p = delegate { return true; };
        
        //this will always work because we are always returning true
        if(p("petar"))
            Console.WriteLine("Cool.");

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

What is going on here? We have assigned variable p to a piece of code! You can see the lambda version and the anonymous way of expressing this fact. In fact, the most common use of this delegate is in the LINQ queries.

image

Notice the expected input into where is the predicate. Here is the LINQ query which will return all elements of the list:

class Program
{
    static void Main(string[] args)
    {
        var list = new List<string> {"one", "two", "three", "four", "five"};

        //Predicate expressed as lambda
        Predicate<string> p = testSubject => true;
        
        var i = from item in list
                where p(item)
                select item;
        
        i.ToList().ForEach(Console.WriteLine);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

This example returns items in the list where the item length is greater than 3.

class Program
{
    static void Main(string[] args)
    {
        var list = new List<string> {"one", "two", "three", "four", "five"};

        //Predicate expressed as lambda
        Predicate<string> p = testSubject => testSubject.Length > 3;
        
        var i = from item in list
                where p(item)
                select item;
        
        i.ToList().ForEach(Console.WriteLine);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

The next example I have two predicates. In the first predicate, I have written and anonymous method that uses the local list to test for its length and then examines the input string if it contains "ee" and the second predicate is a lambda expression testing the subject is greater than number six. Then both of these predicates are combined in the LINQ query to filter the list result.

 
class Program
   {
       static void Main(string[] args)
       {
           var list = new List<string> { "one", "two", "three", "four", "five", "six", "seventeen" };

           //Code inside lambda
           Predicate<string> p = testSubject =>
                                     {
                                         if (list != null && list.Count > 6)
                                         {
                                             return testSubject.Contains("ee");
                                         }
                                         return false;
                                     };

           Predicate<int> e = testSubject => testSubject > 6;


           var i = from item in list
                   where p(item) && e(item.Length)
                   select item;

           i.ToList().ForEach(Console.WriteLine);

           Console.WriteLine("Done.");
           Console.ReadLine();
       }
   }

Ability to assign code to the delegate is very powerful.

The Func

The Func delegate is the probably most powerful of all. Func is also found in the System.Core assembly that comes with in .NET framework version 3.5. While the action never returns the result, predicate always returns bool, Func can return any type (TResult). It also has zero or up to four input parameters.

image

In the example below I am mimicking the Predicate delegate functionality

class Program
{
    static void Main(string[] args)
    {
        var list = new List<string> { "one", "two", "three", "four", "five", "six", "seventeen" };

        Func<string, bool> predicate = testSubject => true;

        var i = from item in list
                where predicate(item)
                select item;

        i.ToList().ForEach(Console.WriteLine);

        Console.WriteLine("Done.");
        Console.ReadLine();

    }
}

And as a final example here is the function that takes IEnumerable and string as an input and returns bool as the result of some logic.

class Program
{
    static void Main(string[] args)
    {
        var list = new List<string> { "one", "two", "three", "four", "five", "six", "seventeen" };

        Func<IEnumerable<string>, string, bool>
            predicate = (items, item) =>
                            {
                                if (items != null && items.Count() > 6)
                                {
                                    return item.Contains("ee");
                                }
                                return false;
                            };

        var i = from item in list
                where predicate(list, item)
                select item;

        i.ToList().ForEach(Console.WriteLine);

        Console.WriteLine("Done.");
        Console.ReadLine();

    }
}

Use Func instead of your custom delegates wherever you can. Func<cool> you = are => cool.

I don't want to make this a monster post but it's worth mentioning these delegates as well: Expression<T>, Comparison<T>, Converter<TInput, TOutput>, EventHandler<TEventArgs>.

In conclusion, there are some good reasons these delegates exist. Certainly is to make LINQ possible but the main reason is that you should stop writing your own custom delegates and use these generic ones. Brad Adams talks more about this his blog post "Framework Design Guidelines: Avoiding custom delegates" found here.

No contrived examples have been hurt in making this blog entry.

 
Posted by Petar Vucetin

Thursday, 29 Jan 2009 10:11 by Khalid Abuhakmeh
Very good explanation. It is very powerful stuff; this stuff makes me glad I am a .NET developer. :)

Thursday, 29 Jan 2009 03:50 by Mike
outstanding post. all the msdn in the world could never teach me in such a suave manner

Thursday, 29 Jan 2009 05:37 by SuperJason
Func<cool> you = are => cool That doesn't compile :-(

Thursday, 29 Jan 2009 10:44 by Duy Lam
Cool post. But there is a minor thing I'd like to say :-). We all know there are several Action delegates and Action<T> is in 2.0 while the rest are in 3.5

Friday, 30 Jan 2009 11:05 by Ike Casteleyn
You're right. The only one that exists in .net 2.0 is the Action<T>. But there's nothing stopping you from putting it in youself. Just put the code below in a common assembly. Below you'll find examples. Just go to the msdn page and copy the declarations from there and you're set. public delegate void Action<T1, T2, T3, T4>( T1 arg1, T2 arg2, T3 arg3, T4 arg4 ); public delegate TResult Func<T1, T2, T3, T4, TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4 );

Friday, 30 Jan 2009 01:22 by boj
"Func<cool> you = are => cool That doesn't compile :-(" Yes, it means that you have to use VB6.

Monday, 2 Feb 2009 12:57 by Mene
How can I write Action<out T>? If I want to have a delegate with an output parameter, I need to declare it first. I can't user Action<out T>. Too bad.

Wednesday, 4 Feb 2009 02:50 by Miron
Nice post. Good to know the names of what we are using on daily manners. Thanks

Friday, 6 Feb 2009 07:02 by Philip
Very well explained, keep it up.

Monday, 23 Feb 2009 04:18 by taelor
great post. I am a ruby developer coming to the C# world, and its really hard to figure out how to do things that seem to easy in ruby, but yet kinda foggy in C#. Thanks for clearing the way. P.S. You guys outta check out the way ruby does things. I think learning both languages is really making me a better programmer.

Thursday, 12 Mar 2009 01:01 by Richard Guion
Great explanation and examples of these delegates. Please keep on writing.

Sunday, 15 Mar 2009 01:25 by Alcide
Very valuable post. Thank you! Now I can finally work with delegates.

blog comments powered by Disqus