C# 3.0 will be hitting the shelves in a matter of weeks, and with it a host of new features. Features that are grounded on features already in C# 2.0. Skip to the facts: if you don’t understand generics and anonymous delegates (and ergo predicates) you are not going to understand C# 3.0 as well as you should.
While generics are easy (just start playing with List<> in System.Collections.Generic and feel the love), anonymous delegates and predicates take some getting used to. Mostly because they are not as easy to explain and they look funny.
The basics are this: Anonymous Delegates allow you to pass code into an existing method. You will see specific examples of anonymous delegates in the form of Predicates and Comparision.
The best place to see this in action is in the previously mentioned generic list class "List<T>". The generic list basically make a dynamic array/collection that is strongly typed to whatever type you give the generic list. So if you want a collection of integers you type:
List<int> myList = new List<int>();
And off you go. But as you go, you should notice a few little gems in the List class. Things like Sort, Find, and Exists. If you lookup the definition of Exists (to pick on at random) you will see something like this:
public bool Exists(Predicate<T> match);
A predicate is a specific anonymous delegate that take an object and returns a boolean. Its declaration looks like this:
public delegate bool Predicate<T>(T obj);
Remember what I said earlier: a predicate allows you to pass in code to an existing method. The delegate Predicate defines what that code must look like. A method that takes an object (as defined by the type passed into the list) and return a boolean. Here is how you use it.
myList.Exists(delegate(int obj) { /* do something cool here */ })
The most common use for an Exists method is to find if a particular value exists in the list. For our case…say the number 5. You would then write this:
myList.Exists(delegate(int i) { return i == 5; })
So where is the anonymous delegate I was just talking about? Here it is all by itself:
delegate(int i) { return i == 5; }
It should look vaguely like a function declaration if I write it slightly different. Compare an anonymous delegate to a method returning a boolean:
delegate(int i) { return i == 5; } |
bool MethodName(int i) { return i == 5; } |
Don’t be fooled to thing we can just see if one value is the same as some other arbitrary value. You just have to return a True or a False. If you want to know if any value is greater than 700, not a problem. Just return True or False.
What does this buy us?
While showing the use with a List of integers does make things nice and simple, what if we are dealing with a list of objects? If you have a customer object with a FirstName and LastName, how do you sort it? More importantly, how would a generic list object know how to sort it? It can’t. Not until that ESP module finally gets finished anyway.
What this buys us is flexibility to perform our esoteric business logic on complex objects. That is where anonymous delegates really start to shine.
Caution in the wind
Now that I’ve talked about the wonders that anonymous delegates can be, please use with caution. When misused they can turn into a 3 headed, fire breathing monster. Specifically I’ve seen many a developer try to write their own methods that take anonymous delegates to pursue the DRY (don’t repeat yourself) principle to ends unknown.
For example: if you are writing an anonymous delegate to save yourself a ‘for’ loop, you might be a redneck — wait, that came out wrong. But you will have developers give you dirty looks once you check in, ok.
If you want an example if this, Jason Grundy wrote about this a while back.
Back to C# 3.0
What does this have to do with C# 3.0? Everything that is Lambda and LINQ. Lambda is nothing but a cleaner way of writing anonymous delegates. Really. That is it.
My previous example moves from
myList.Exists(delegate(int i) { return i == 5; })
to a lambdaified (lambdaified: not a word yet, but it will be)
myList.Exists( x => x == 5)
Simple, clean, elegant. The lambda version is anyway. Now, if you don’t understand the x => x == 5, that is pure Lambda, and you will hearing a lot more about that in the near future.
Great article, Chris.
Can you expound a little bit on how anonymous delegates specifically support DRY?
Am I going to learn that when I click the link to Jason’s article?
🙂
Thank you Chris! I appreciate that you also delved into Lambda expressions!