Wednesday, 9 June 2010

Automatic collection mapping for your mappers

I was going through our code base the other day and found a large number of mapper objects and their related interfaces. They all looked something like this:

public class SomeObjectMapper
{
    public ObjectA Map(ObjectB source)
    {
        //Perform mapping and return.
    }
 
    public IEnumerable<ObjectA> MapAll(IEnumerable<ObjectB> source)
    {
        return source.Select(x => Map(x));
    }
}

Most of the mappers followed this general style but were inconsistent with mapping method names or what type of collection they returned (ICollection, IList, etc) and how they traversed the collection (for, foreach, linq).

First of all I wanted to bring some form of consistency to the mappers so I introduced an IMapper<,> interface, this is quite common and can be seen in many examples on the blog sphere.

public interface IMapper<TInput, TOutput>
{
    TOutput Map(TInput input);
}

Secondly I wanted to remove the need of the duplicate code for mapping one enumeration/list/collection to another. I could have introduced a base class but because all the mappers now use an interface I can use an extension method which would be far more flexible than a base class.

public static class MapperExtensions
{
    public static IEnumerable<TOutput> MapAll<TInput, TOutput>(this IMapper<TInput, TOutput> mapper, IEnumerable<TInput> input)
    {
        return input.Select(x => mapper.Map(x));
    }
}

Whilst this wont work for all mappers it does provide a way of cleaning up most common mappers so that they conform to the same signature and deal only with the one task of mapping object A to object B without having to be cluttered with mapping collections.

No comments:

Post a Comment