Getting Familiar With Your Basic .NET Delegates
The .NET framework is a complete toolbox of programming constructs that allows a developer to create any kind of software. You’re practically limited by your imagination and knowledge on the framework. Such a knowledge can be satisfied by getting more familiar with its interfaces, abstract classes, concrete types, events and delegates. In this post, I want to concentrate on inviting you to get familiar with some basic and powerful delegates provided by the .NET framework. The reason of this post is that I often see developers create their own delegates that have the same semantics of the ones provided in the framework mostly because they aren’t aware of them. Instead of violating the DRY principle of programming, let’s discover and learn about them so that we can avoid reinventing the wheel.
The set of basic delegates that I think .NET developers should be familiar and comfortable using are the generic Action<T>, Comparison<T>, Converter<TInput, TOutput> and Predicate<T> delegates. I will introduce you to each of these delegates by describing their usage with a simple example so that you can start using them in your codebase where needed.
The Action<T> delegate
In .NET 2.0, the Action delegate, declared in mscorlib.dll, has the following signature:
public delegate void Action<T>(T obj);
When Microsoft released .NET 3.5, four more Action delegates were included in System.Core.dll:
public delegate void Action()
public delegate void Action<T1,T2)(T1 arg1, T2 arg2)
public delegate void Action<T1,T2,T3)(T1 arg1, T2 arg2, T3 arg3)
public delegate void Action<T1,T2,T4)(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
Regardless of the different signatures of the Action delegate, its semantic is to encapsulate a method which doesn’t return a value, and which holds a variable number of parameters:
- If the method is parameterless, you should prefer the Action delegate.
- If the method accepts one parameter, you should prefer the generic Action<T> delegate.
- If the method accepts two parameters, you should prefer the generic Action<T1, T2> delegate.
- If the method accepts three parameters, you should prefer the generic Action<T1, T2, T3> delegate.
- If the method accepts four parameters, you should prefer the generic Action<T1, T2, T3, T4> delegate.
- If the method accepts five (or more) parameters, you should prefer reviewing your design
A quick analysis with Reflector on the these delegates show that only the Action<T> delegate is being used by .NET in a couple of places, notably as a parameter for the ForEach method of both the static Array class and the generic List<T> class. The other locations where this delegate is being used aren’t publicly accessible, so we will restrain ourselves to understanding the use of this delegate with a simple usage with the ForEach method of the generic List<T>.
Suppose we have a collection of toys which we want to iterate to display each of its name on the console. A possible solution to satisfy this requirement without using the Action<T> delegate could be:
// Create our toys collection List<Toy> toys = Repository<Toy>.FetchAll(); // Not that important how we get our toys collection here // Iterate through the collection using a foreach statement and display each toy's name on the console foreach(var toy in toys) { System.Console.WriteLine(toy.Name); }
The above solution works and your unit tests should pass. But does it warrant a check-in to the source code repository? This code we have written to satisfy the requirement seems to me very imperative, almost like how a robot would think. I am mixing both the “how” and the “what” in this context. For instance, I am iterating on the collection with a foreach statement (the “how”) in order to fulfill my intent which is to display the toy’s name on the console (the “what”). Since my brain is better at processing one information at a time, I rather focus on the intention rather than the implementation. Maybe we can hold on that check-in and see if there’s a better way to do this.
As a matter of fact, there is. The generic List<T> class defines an instance method which iterates the collection and performs an action for each of its element via an Action<T> delegate. The Array class defines the same method but it is added as an extension method on that type. That being said, if there’s another data structure that implements IEnumerable<T> or IEnumerable which doesn’t have an equivalent of a ForEach method, there’s nothing stopping you from creating one on the type via an extension method. This is the second solution that satisfy this requirement and which clearly brings out my intention forward because I don’t care how the collection is being iterated or what algorithm is used for the iteration, I’m just concerned of doing something with each of its element in a sequential manner.
// Create our toys collection List<Toy> toys = Repository<Toy>.FetchAll(); // Not that important how we get our toys collection here // Display each toy's name in the console (using a lambda expression) toys.ForEach(toy => System.Console.WriteLine(toy.Name)); // You can also use an anonymous delegate to do the same thing...only with more keyboard typing than is necessary toys.ForEach( delegate(Toy toy) { System.Console.WriteLine(toy.Name); } );
Ignoring the instruction using the anonymous delegate, and instead focusing on the one using the lambda expression, we can clearly see that our intention is much clearer. On a side note, I will use lambda expression whenever needed for the following examples to keep them shorter. I just added the anonymous delegate if you weren’t too familiar with lambdas. As you see by using the lambda expression that I don’t have to use the delegate keyword and I can safely rest on the compiler’s type inference functionality which are both a time saver. The bottom line with the Action delegate is that it is there for you to do something (perform an action) on an element. It is commonly used when some action must be performed on an element during an iteration over a collection, but keep in mind that it doesn’t have to be used just in the context of an iteration over a collection. The Action delegate is also a powerful move to consider when, for example, a collection doesn’t offer a specific iterator that you’re looking for, such as an EvenNumberIterator. In this case, for every iterated element, you’ll do something specific if the number is even, such as displaying it on the screen (notice that to use multiple statements with lambdas, those statements should be enclosed within braces):
List<int> numbers = Generator<int>.GenerateSequence( 10 ); // Generate a sequence of 10 random numbers numbers.ForEach( number => { // Display the number only if it's even if ( number % 2 == 0 ) Console.WriteLine( number ); } );
Something to keep in mind with all the parameterized Action delegates is that the parameters are passed by value which means that any modification to anyone of them will only be local to the scope of delegate’s body or the method being invoked by the delegate. In other words, the collection’s items won’t be modified. The multiple parameterized Action delegates introduced in .NET 3.5 allow you to use them in case you need to do something with either two, three or four parameters (they can all be of the same type if needed).
The Comparison<T> delegate
Introduced in .NET 2.0, the generic Comparison<T> delegate is mostly used for sorting elements within a collection. It is currently used by the Sort methods of both the Array and generic List<T> classes. This delegate has the following signature:
public delegate int Comparison<T>(T x, T y)
The nature of the delegate is identical to the IComparer<T>.Compare method in that:
- if x > y, then a positive value is returned (traditionally that value is 1);
- if x < y then a negative value is returned (traditionally that value is -1);
- in the case where both x and y are equal, a value of 0 is returned.
This shouldn’t be too much of a surprise because internally the Sort method of both the Array and generic List<T> classes use the generic FunctorComparer<T> to wrap the delegate so that it can be used as an IComparer<T> object internally. When the IComparer<T>.Compare method is invoked by .NET, it is actually the Comparison<T> delegate that is fired. Pretty neat, uh? The semantic of using this delegate (or the IComparer interface for that matter) is to define an alternative order for sorting elements within a collection. Getting back to our toys collection, suppose we want to sort them by name (a string). We could provide the following code to satisfy this requirement:
List<Toy> toys = Repository<Toy>.FetchAll(); // Again it doesn't matter how we get our toys // using a lambda expression to define our sorting algorithm toys.Sort((x, y) => { if (x == y) return 0; if (x == null) return -1; if (y == null) return 1; return x.Name.CompareTo(y.Name); } );
This solution is great if you only have one sorting strategy and you foresee that it will not change in the future. But there’s a better way to use this delegate. In fact, the power of the Comparison<T> delegate is that…it’s a delegate! This means that we can do some crazy and complex sorting if we must by combining various strategies! What if we want to sort our toys first by name, then by price and also by a different criteria? Using a lambda expression is asking way too much trouble. Let’s see how we can take advantage of the Comparison<T> delegate in this case. Let us now sort our toys by name, then by price.
private static void Main(string[] args) { List<Toy> toys = Repository<Toy>.FetchAll(); // Again it doesn't matter how we get our toys // Instantiate our Comparison<T> delegate in a way that we want to sort our toys by name (first order), then by price (second order) Comparison<Toy> comparison = CompareToysByName; comparison += CompareToysByPrice; toys.Sort(comparison); } // Compare two toys by name private static int CompareToysByName( Toy x, Toy y ) { if (x == y) return 0; if (x == null) return -1; if (y == null) return 1; return x.Name.CompareTo(y.Name); } // Compares two toys by price private static int CompareToysByPrice( Toy x, Toy y ) { if (x == y) return 0; if (x == null) return -1; if (y == null) return 1; return x.Price.CompareTo(y.Price); }
This is awesome because we can simply mix our sorting strategies through a simple delegate which will be used as a parameter to the Sort method of both an Array and generic List<T> classes. Once the Sort method has finished its job, your collection will be sorted by the criteria you have specified.
The Converter<TInput, TOutput> delegate
The next delegate that I would like to be familiar with is the generic Converter<TInput, TOutput> delegate which was introduced in .NET 2.0. Just like its other counterparts, this delegate is being used by both the Array and generic List<T> classes, more specifically in their ConvertAll<TOutput> methods. The signature of the Converter<TInput, TOutput> delegate is as follows:
public delegate TOutput Converter<TInput, TOutput>(TInput input)
This delegate is useful whenever you have to define a strategy to convert an object from one type to another type. For example, you might want to convert an object of type System.Int32 to a type System.String. Continuing with our toys example, let us consider the following simple requirement: we want to create a list containing only the names of every toy from our toys collection.
List<Toy> toys = Repository<Toy>.FetchAll(); // Not really important how we get all our toys. List<string> toysNames = toys.ConvertAll(toy => toy.Name);
It’s that easy! Our strategy is basically that given a Toy (this is our closed type for TInput), we’ll return a String (this is our closed type for TOutput). Just like we have done with the Comparison<T> delegate example, you can also mix in some conversion strategies. Just remember that variance on delegates isn’t supported in C# 3.0. For more information on this topic, I strongly suggest you to read Eric Lippert’s eleven-part posts on covariance and contravariance.
The Predicate<T> delegate
Though being used once again by the Array and generic List<T> classes, the generic Predicate<T> delegate is more used by the framework than the three other ones. This delegate represents a method that defines a set of criteria and determines whether the specified object meets those criteria. You can also see this delegate acting like a filter on a collection. The signature of the Predicate<T> delegate is as follows:
public delegate bool Predicate<T>(T obj)
Like I said, the .NET framework uses this delegate in both the Array and generic List<T> classes in many of their methods (Exists, Find, FindAll, FindIndex, etc.). In short, you provide an evaluation context for a parameter where you either return true if the condition for that parameter is met, false otherwise. Continuing with our toys example, suppose that we want to 1) find out whether we have a toy with a specific name and year, and 2) find all the toys that were made in Canada. We could simply use the provided methods (Exists and FindAll) and passing them a Predicate<T> delegate that will contain our logic for evaluating whether or not the condition is satisfied.
List<Toy> toys = Repository<Toy>.FetchAll(); // We're not particularly interested in knowing how we got our toys. // 1. We're interested in knowing whether we have my favorite Transformer of all: Megatron! // I have a couple of them, but I'm specifically interested in the one my parents bought me in 1985. bool containsMy1985Megatron = toys.Exists( toy => toy.Name == "Megatron" && toy.Year = 1985 ); // 2. We're now interested in retrieving all our toys made in Canada. List<Toy> myDecepticons = toys.FindAll( toy => toy.Country == "Canada" );
By simply invoking those methods and passing them a Predicate<T> delegate, I can concentrate on what I want in a more declarative way because I don’t have to explicitly iterate/loop over the collection with either a foreach statement, a for loop, a while loop, etc. I just want to iterate over my toys, and either find out if a match was found or retrieve all my toys that satisfy some condition. This last statement is also true for any of the other delegates that I presented here.
Conclusion
In this post, I wanted to familiarize you with some of the basic delegates that are offered by the .NET framework BCL (outside of ASP.NET, ADO.NET, etc.) that allow you more flexibility in specifying different strategies for various contexts (such as in finding, retrieving, converting or performing an action to an element of a collection). In other words, these delegates allow me to concentrate more on the business logic rather than, for example, writing the plumbing necessary to iterate over a collection, because they are commonly used as a parameter to a method which already implements the plumbing on my behalf.
Whether I’m consulting with companies or training developers, more often than not I see these kind of delegates redefined in code because the developers were completely ignorant of the existence of these delegates! That’s too bad, because violating the DRY principle forces you to document, test and maintain more code than you would actually need in your codebase. Remember that the .NET framework isn’t solely C#. The .NET framework is a huge toolbox that provides you with many tools (interfaces, classes, events, delegates, etc.) to build various applications. The more you know about those tools and how to use them properly, the better your code will be and the more valuable you will become to your organization and team.
For more information on delegates, I highly recommend you the following links:
- Get a copy of More Effective C#: 50 Specific Ways to Improve Your C# by Bill Wagner. More specifically, take a look at Item 18: Decouple Iterations from Actions, Predicate, and Functions to get a better understanding of Action, Predicate and Func delegates.
- Get a copy of C# in Depth by Jon Skeet. This is one guy who has been very helpful in the .NET community by writing many useful articles and also published, in my opinion, the best practical book on C# 2.0/3.0 to date.
- Check out dnrTV’s episode on events and delegates with Mark Miller.
Similar posts you might be interested in reading:
- Explicit Interface Members Implementation in C#
- Avoid calling a virtual or abstract method from a constructor in C#…especially in VB!
- Null Coalescing Operator
- String vs StringBuilder for the .NET Concatenation Performance Championship
- Evolving your design with the Principle of Least Knowledge
- Inserting and Retrieving An Image In SQL Server 2005
- Rely on your experience and knowledge over some tools’ recommendations






DotNetShoutout:
Brian On Software » Blog Archive » Getting Familiar With Your Basic .NET Delegates…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
[WORDPRESS HASHCASH] The comment’s server IP (206.72.113.4) doesn’t match the comment’s URL host IP (206.72.113.143) and so is spam.
February 2, 2009, 8:18 amPaul:
Great article! One thing I’ve noticed when teaching Lambdas is that the students tend to “get it” quicker when I use parens for the parameters, even if there’s only one:
(toy) => { … }
instead of:
toy => { … }
Something about having the parameters in parentheses makes it click for them.
February 2, 2009, 3:22 pmThomas Johnson:
Thanks for that article very helpful, I’ve just recently started with c# and I’m just beginning to realise how many useful features are already built in.
February 2, 2009, 5:42 pmSanjayU:
Great article. Keep up the good work.
February 2, 2009, 6:04 pmBrian Di Croce:
@Paul: Great idea with adopting the parenthesis for the parameters. Since you need them when there are multiple parameters, I think it is wise to adopt them even for single parameters, especially to avoid confusion amongst first-time learners. I wonder what is there’s a guideline for this…
@Thomas: You’re welcome! I’m glad it helped.
@Sanjay: Thanks!
February 3, 2009, 6:56 amDew Drop - February 3, 2009 | Alvin Ashcraft's Morning Dew:
[...] Getting Familiar with Your Basic .NET Delegates (Brian Di Croce) [...]
[WORDPRESS HASHCASH] The comment’s server IP (72.47.228.17) doesn’t match the comment’s URL host IP (72.47.228.144) and so is spam.
February 3, 2009, 9:54 amKurt:
As someone who just today violated the DRY principle because I was only vaguely aware of or not completely comfortable with these tools, thank you for the great article!
February 4, 2009, 10:07 pm