Neighbourhood super-hero LINQ comes to the rescue
I was just reading Mike Stall's blog Fun with yield, generics, foreach. He discusses using enumeration with yield and generics. The example he uses is a heterogenous array object[] list = new object[] {1,2, "abc", 5f, "def" }; and he needs to print all the strings in it. The simple solution in C#1.x is
object [] list = new Object[] { 1, 2, "abhinaba", 5f, "basu" };foreach (Object o in list) { string s = o as string; if (s == null) continue; Console.WriteLine(s); }
Initially I was kind of opposed to the whole idea of LINQ. I think this is the mental adoption blocker which everyone talks about. As time is passing and I am being forced to use C#2.0 (we have not yet moved to 3.0) everyday I get the urge to use LINQ as it solves many problem so elegantly. If we use C#3.0 we can do this as follows
object[] list = { 1, 2, "abhinaba", 5f, "basu" }; foreach( var v in list.Where(x => x is string)){ Console.WriteLine(v);}
This code uses some of the new C#3.0 features. Where is a System.Query provided extension method which you can add to any collection. x => x is string is a lambda expression which is passed as the predicate to the extension method. Here type parameters of the predicate is inferred from the lambda expression.
After writing this code I just felt happy. I think the greatest achievement for any language is that it makes programmers who use it happy, what more can you ask for?
<Edit : Some additions>
I asked what more you can ask for and Theme over on the original Mike's post suggested that the foreach can be further reduced. I took the hint and cooked up the following
public delegate void Action<T>(T val);static class MyExtensions{ public static void ForEach<T>(this IEnumerable<T> list,
Action<T> act) { foreach (T t in list) act(t); }} object[] list = { 1, 2, "abhinaba", 5f, "basu" };
list.Where(x => x is string).ForEach(Console.WriteLine);
So if I have the Extension method ForEach handy in some assembly/source or if I can find the equivalent in System.Query namespace then I have reduced the solution to 2 lines. Since the whole of it is generics based and Console.WriteLine have enough overloads the solution works fine with data types other than string (like int).
I asked for more and got more. Bring on C#3.0, 2.0 is already stale and its time to replace it...
Comments
- Anonymous
January 31, 2006
What we can ask for is for MS to get moving on C# 3.0. Once a week we use our test development machine with the linq preview installed to find new ways to cut down code and can't wait till it gets mass adoption. - Anonymous
January 31, 2006
After upgrade of our blog server I'm seeing that the code formatting is getting wrong at some places. Lines are breaking at places where it shouldn't. Could be a css issue. I'll try to see if I can get that fixed.... - Anonymous
March 10, 2006
I don't believe that code would even compile.
The ForEach would require a type.
Would have to at least be:
ForEach<string>(Console.WriteLine)
And I'm not even sure ...
But I would imagine that the WriteLine would have to be templated to even work.
Did you actually compile this or just theorize it? - Anonymous
March 10, 2006
Brian, Do you really think I'd post code here if it didn't even compile. You should trust Microsoft programmers a bit more :)
It does compile and the reason are as follows
Why type is not required as in ForEach<string>
The reason is simple it uses Type inference. See http://blogs.msdn.com/abhinaba/archive/2006/01/10/511156.aspx
Why WriteLine does'nt need to be templated
That even simpler. I've mentioned it in the post above. If the type T is such that there is an overload as in WriteLine(T t) then the code compiles.