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.
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).
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.
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 )
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.
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.
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.