Alex Hoffman

Perspective on management, development and technology

Syndication

News

    Subscribe

    IASA Member

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?

Published Monday, August 06, 2007 2:36 PM by Alex Hoffman

Filed under: , ,

Comments

# re: Adventures in .NET 3.5 Part 3@ Monday, August 06, 2007 9:35 AM

great. Really cool

Vikram

# re: Adventures in .NET 3.5 Part 3@ Monday, August 06, 2007 12:42 PM

Why not use Func<T,T1> instead of creating the named transform delegate?

Also, you could have used System.Converter<,> delegate with the same type as both type arguments.

Jay R. Wren

# re: Adventures in .NET 3.5 Part 3@ Monday, August 06, 2007 7:57 PM

@Jay

I could have used Func<T,T> but I thought it would only complicate the discussion.  I'm going to discuss a method that can do both 'transformation' as well as 'conversion' next - that will use Func().

Alex Hoffman

# Adventures in .NET 3.5 Part 4@ Monday, August 06, 2007 10:03 PM

This is the 4th part in a series. See Part1 , Part 2 and Part3 . Extension Methods continued So, where

Community Blogs