Adventures in .NET 3.5 Part 4

This is the 4th part in a series.  See Part1, Part 2 and Part3.

 
Extension Methods continued 

So, where we left things last time, was with the creation of a Transform() extension method that allowed us to output to the console, lowercase states transformed from uppercase ...

     new[] { "NSW", "WA", "QLD", "SA", "TAS", "VIC" }
       .Transform( s => s.ToLower() )
       .Concatenate(", ")
       .Print("States: ");       // outputs... States: nsw, wa, qld, sa, tas, vic

Or to just to get back a new collection ...

     var lowerstates = new[] { "NSW", "WA", "QLD", "SA", "TAS", "VIC" }.Transform( s => s.ToLower() ); 

But, the way I've implemented the Transform() method, we can't change the type of resulting collection - something I want to do.

For example, I'd like to be able to create a new collection with the lengths of the state names as ints instead of strings.  Or given some dates, I'd like to be able to get back a collection of the day names of each date as strings.

Also, I'm not too happy with the method name Transform().  We have previously created an extension method named Each() that takes an Action() delegate.  Lets, overload Each() so that we have just one method name to remember.  The following extension method will give me what I need ...

     public static IEnumerable<TResult> Each<T, TResult>(this IEnumerable<T> items, Func<T, TResult> function)
     {
         foreach (var item in items)
         {
             yield return function(item);
         }
     }

While it looks nasty, all one has to remember is how to use it.

We can now type as before ...

     var lowerstates = new[] { "NSW", "WA", "QLD", "SA", "TAS", "VIC" }.Each( s => s.ToLower() );

or

     new[] { "NSW", "WA", "QLD", "SA", "TAS", "VIC" }
       .Each( s => s.ToLower() )
       .Concatenate(", ")
       .Print("States: ");       // outputs... States: nsw, wa, qld, sa, tas, vic

But we can also do the following to convert the following strings to decimals ... 

     new[] { "1.34", "3.79" }
         .Each<string, decimal>( i => Convert.ToDecimal(i) )
          .Concatenate(", ")
         .Print("Decimals as Strings: ");     // outputs... Decimals as Strings: 1.34, 3.79

 
 The Each() method above specifies the Type to convert from, and the Type to convert to, and the lambda performs the conversion.

 As another example, consider the following ...

      new[] { "jan 1 2002", "Aug 17 2007", "Feb 18 2045" }
         .Each<string, DateTime>( i => DateTime.Parse(i) )
         .Each<DateTime, DayOfWeek>( i => i.DayOfWeek )
         .Concatenate(" to ")
         .Print("Days: ");                    //outputs... Days: Tuesday to Friday to Saturday

Here, the first Each() method parses each date string and converts it to a DateTime, then the second converts the DateTime to a DayofWeek enum which is then output to the console.  One can string together multiple Each() methods, each modifying or acting on the collection contents.

And as before, one can still have Each() perform an action ...

     new[] { 1, 2, 3, 4 }.Each( i => i.Print() );
 

I'll tidy up, add exception handling and publish the code for all this shortly.

1 Comment

  • If I understand this correctly then Each creates a new "array", so when you say ".Each(i => DateTime.Parse(i) }" I get a new list and the original is kept. It is possible to change the original list? If I say ".Each( s => s.ToLower() )" I'd like to change the original and not get a new copy...

    Thanks.

Comments have been disabled for this content.