C# 3 gave us the lambda expression and ever since we have been using them to create abstract representations of terse, anonymous functions.
While expressive and helpful, they are not always needed. Consider this example:
using System; using System.Collections.Generic;
class Example { static void Main() { new List<Int32> { 1, 2, 3 } .ForEach(i => Console.WriteLine(i)); } }
The preceding code can be refactored to this:
using System; using System.Collections.Generic;
class Example { static void Main() { new List<Int32> { 1, 2, 3 } .ForEach(Console.WriteLine); } }
What is different? In the second example we are simply passing the name of the method group that we wish to invoke. Since List<T>.ForEach accepts a single parameter of type Action<T> we can leverage the flexibility afforded us by the C# compiler to pass a method group name (in this case Console.WriteLine) to this method. The compiler helpfully creates the new Action<Int32> delegate behind the scenes.
In this instance refactoring doesn’t improve performance (in fact, the resulting IL is identical), but it does present a more readable expression (it is in fact an excellent example of declarative programming). So I challenge you to find opportunities to forgo lambda expressions. If you find yourself writing lambda expressions that look similar to the one I have used in the example, stop and evaluate it carefully to see if you really need it.
You will find this mental exercise rewarding as it will not only improve the expressivity of your code, but it will also force you to think carefully about its functional nature.
Caveat: Since C# 3 does not support the ability to infer generic type arguments from the return types of method groups, this really only works for examples like I have posted. They work because the examples allow type inference to be accomplished based on the types of the method’s arguments.
In other words, C# 3 will only let you do this for methods that accept delegates in the Action family (i.e. Action, Action<T>, etc.) since these delegates do not return any values. Revisions to the type-inference algorithm in the C# 4 compiler changes this and opens up a lot of possibilities. Check back soon for another article that will cover this topic in depth.
Edit: Here is the follow-up article: Smarter type inference with C# 4.
4 Comments
Personally I prefer the first example. It’s more explicit. I like explicitness!
You know that ReSharper suggests this fix?
@David Kemp – No, I didn’t know that! Very cool!
Delete all files on your C drive:
Directory.GetFiles(“C:\\”, “.“, SearchOption.AllDirectories).ToList().ForEach(File.Delete);
I’m kidding of course, as you’ll get all kinds of security issues, but cool nonetheless :-)
Post a Comment