Adventures in .NET 3.5 Part 3

This is the 3rd part in a series.  See Part1 and Part 2

 
Inferring a Collection Type

In C# 3.5, the compiler can (typically) infer the type of a collection.  The member type doesn't need to be explicitly specified.

     var nums = new[] { 1,2,3 };
 or
     var states = new[] { "NSW", "WA", "QLD", "SA", "TAS", "VIC" } ;
 
We could now apply the Concatenate and Print extension methods from Part 1, in order to create an array, and output it to the console in a single line ...

     new[] { 1,2,3,4,5 }.Concatenate().Print();       // displays: 12345
 

Transforming the Collection

What I'd now like to do, is be able to easily transform the collection. For example, using the "states" array declared earlier, I'd like to be able to say something like...

     var lowerStates = states.Transform( s => s.ToLower() );

Or, double each of those "nums" ...

     var doubled  = nums.Transform( n = > n *= 2 );

Out of the box I haven't been able to do that.  Sure you could use the Array.ConvertAll() method, but that doesn't provide the neat syntax I'm after.

So what to do?  The Each() extension method I created in the previous post won't work either, because it simply accepts an Action delegate that returns void.  The framework Predicate delegate doesn't help either because it returns a bool

3.5 introduces a general Func() delegate that we might use later, but for now what we really need is a delegate of T that returns T, so I'll create one.

     public delegate T Transformation<T>(T obj);

Now that we have that, we can create an extension method that meets our needs ...

     public static IEnumerable<T> Transform<T>(this IEnumerable<T> items, Transformation<T> transform)
     {         
         foreach (var item in items)
         {
             yield return transform(item);
         }
     }


Let's convert those states to lowercase, and as before apply the Concatenate() and Print() methods to output lowercase states to the console

     states.Transform( s => s.ToLower() )
       .Concatenate(", ")
       .Print("States: ");       // outputs "States: nsw, wa, qld, sa, tas, vic"


I haven't touched on LINQ yet, but it introduces a new standard query syntax.  We can use some of the extension methods built in to the framework to support it to further enhance our previous statement.  Note the framework Where() and OrderByDescending() extension methods below.  Any guesses as to the output?

     states.Transform( s => s.ToLower() )
       .Where( i => i.Contains("w") )
       .OrderByDescending( i => i )
       .Concatenate(", ")
       .Print("States: ");       // outputs ?


The Transform method returns an IEnumerable of T, where T is the same type as the initial collection.  So one cannot (as implemented) convert a collection of state names to a collection of another type - say integers that represent the lengths of the names.  Wouldn't it be good if we could do that as well?

3 Comments

Comments have been disabled for this content.