25 January 2010

A generic convertor for IEnumerable<T>

Apart from ForEach<T>, as I described in my previous post, I noticed the absence of ConvertAll<T> on everything but List<T> as well. Pretty annoying when I wanted to convert a list of business objects of So I extended my static class GenericUtilities with another extension methdo

using System;
using System.Collections.Generic;

namespace LocalJoost.Utilities
{
  public static class GenericExtensions
  {
    // previous code for ForEach omitted.

    public static IEnumerable<TC> ConvertAll<T, TC>(
      this IEnumerable<T> inputList, 
      Converter<T, TC> convert)
    {
        foreach( var t in inputList )
        {
            yield return convert(t);
        }
  }
}
This permitted me to do something like this:
return ListRubriek.Get()
  .ConvertAll(p => new CascadingDropDownNameValue(
        p.Omschrijving, p.Id.ToString()))
  .ToArray();
to easily convert a list of CSLA business objects into a list that could be used in an ASP.NET Ajax Cascading dropdown. Nothing special for the veteran functional programmer I guess but still, useful.

This is actually the 2nd version - thanks to Jarno Peschier for some constructive criticism

2 comments:

peSHIr said...

Your convert sounds a bit like a generic mapper function, often called map() in functional languages. In .NET this is part of System.Linq as the Select() method. You might be able to use that: simply supply a suitable lamdba that converts from one type to another.

peSHIr said...

Oh, and another thing: if you define a method returning IEnumerable you are doing more than callers might expect if you construct a List and then return that. It reserves memory for a complete List instance. In your own example you're only interested in an array, so this List is created "in vain".

I would implement the method using a foreach statement in which you yield return the elements instead of constructing and returning a List. This would give you the same lazy evaluation characteristics as LINQs select: as long as you do not enumerate the sequence nothing is actually done. And the caller can always use ToArray() or ToList() to get an actual collection instance as needed.