Converting IEnumerable to IEnumerable

This morning on the forum there was a question regarding nullable types (ie decimal?) and how to convert an IEnumerable collection containing nullable types to one containing the equivalent non-nullable type (decimal).  This raised an interesting question, how do you convert a collection containing one type of object, into a collection containing another type of object, be it nullable>nonnullable or otherwise.

To start with, I looked at the extension methods of IEnumerable, and in particularly Cast<>.  However, if the value is null then we are going to have to handle it differently which cast doesn’t have the ability to do.  So no luck there and there didn’t seem any other methods.

I then looked at the methods which List<> contains, this implements IEnumerable<> so its part of the same type.  List<> does have a method which allows for this requirement, called ConvertAll() which takes a Converter object, which in turn takes a method name which is called for each object in the list to handle the conversion.  This then allowed me to write this code:

List nonNull;
List nullable = new List();

nullable.Add(null);
nullable.Add(1);

nonNull = nullable.ConvertAll(new Converter(ConvertToNonNull));

foreach (var i in nonNull)
{
   Console.WriteLine(i);   
}

public static decimal ConvertToNonNull(decimal? nullValue)
{
    return nullValue.GetValueOrDefault(0);
}

ConvertToNonNull is called for every item in the list, taking advantage of generics to keep everything strongly typed.  The GetValueOrDefault() is available to use on all nullable types, you simple give it the value as a parameter you want it to return if the value is null.

The problem is that you have to be working in terms of List<> and not IEnumerable<>.  The solution, create your own extension method for IEnumerable<>.

public static class IEnumerableExtension
{
     public static IEnumerable ConvertAll(this IEnumerable collection, Converter converter)
     {
         if (converter == null)
             throw new ArgumentNullException(“converter”);

         List list = new List();

         foreach (T i in collection)
         {
             list.Add(converter(i));
         }

         return list;
     }
}

The extension method above attaches itself to IEnumerable<> and takes a Converter as a parameter – just the same as List does.  I then check to make sure its not null,  create a new internal list of the outputting type (need a way to hold the converted items internally).  Then for each item in the source collection, I call the converter method.  Finally I return the list as a return type of IEnumerable<>.  Here’s the calling code.

IEnumerable notNull;
IEnumerable INull;

INull = nullable; //Original list.

notNull = INull.ConvertAll(new Converter(ConvertToNonNull)); //My new extension method

foreach (decimal i in notNull)
{
    Console.WriteLine(i);
}

One of the nice things about extension methods is that if a method, with the same name and parameter list, is defined locally within the class then it overrides the extension implementation.  So, the List<>.ConvertAll() functionality is not affected.

Hope you find a use for this.

Technorati Tags: ,

5 thoughts on “Converting IEnumerable to IEnumerable”

  1. Cool. I wonder if this will work in the extension method without the converter argument (I haven’t tried it myself):

    foreach (T value in collection)
    {
    yield return (value == null)
    ? default(TOutput)
    : (TOutput) Convert.ChangeType(value, typeof(TOutput));
    }

    Then you could just use:

    notNulls = nulls.ConvertAll();

    Does that work? (I don’t feel like firing up the VM now… 🙂

  2. Yeah, booting up VMs to try sample code isn’t great.

    Great comment! Including code like below, will create a overload so you can decide to use a converter or just a basic type converstion.
    (Had to remove
    public static IEnumerable TOutput ConvertAll T, TOutput (this IEnumerable T collection)
    {
    foreach (T value in collection)
    {
    yield return (value == null)
    ? default(TOutput)
    : (TOutput)Convert.ChangeType(value, typeof(TOutput));
    }
    }

    However, using a Converter is really useful when doing conversation other than type, maybe pulling data from an additional source. By having it as an overload we get the best of both worlds!

    There is a bit of a problem when calling it. Because it uses two generic types, you have to actually define what they are as it can only infer the base type of the collection.

    You would need to call it like this:

    notNull = INull.ConvertAll decimal?, decimal ();

    Apart from that, neat idea!

  3. I certainly agree that having the converter as an overload would be useful.

    It’s unfortunate about having to specify the generic types though. On well, at least it worked 🙂

    BTW, I’ve been following your posts on 3.5 features and I’m learning some cool stuff.

    Thanks and keep up the good work.

  4. That’s really cool.

    If we only want to add a extension method to convert a list of nullable type into its equivalent non-nullable type, we may just need to add an extension method to the IEnumerable>:


    public static IEnumerable ConvertToNonNullable(this IEnumerable> target) where T : struct
    {
    foreach (Nullable item in target)
    {
    yield return item.GetValueOrDefault();
    }
    }

  5. You’ve inspired me to write implementations of the missing pieces; See C# Coding; Missing Functions on IEnumerable

    I’d suggest that if you have a nullable list, you probably want to strip out the null values, not convert them to zero; null probably indicates ‘the value is not known’, not ‘the value is zero’. You can do this by combining a filter and a convert;

    IEnumerable cleanlist = collection.Filter(x => x.HasValue).Map(x => x.Value);

Leave a Reply

Your email address will not be published. Required fields are marked *