MappingEnumerable

In my infrastructure layer of my projects I regularly include the following interface:

1
2
3
4
public interface IMapper<Input, Output>
{
  Output MapFrom(Input input);
}

This interface should be fairly self-explanatory, it takes in an item of type Input and spits out an item of type Output. For those who care about details (and I do) it is also good to note that this interface matches the signature for a Converter generic delegate.

One of the (many) places that I use implementations of this interface is in the service layer to marshal data back up to the higher level layers as DTOS. Here is an example of a simple Mapper:

1
2
3
4
5
6
7
8
public class DepartmentDisplayItemDTOMapper : IDepartmentDisplayItemDTOMapper
{
  public DepartmentDisplayItemDO MapFrom(IDepartment department)
  {
    return new DepartmentDisplayItemDO
      (department.Name, department.Id);
  }
}

One of the ways that I would have leveraged this in the past would have been to inject the service layer component with the appropriate mapper and then map items that were returned from the repository in place.

Here is another alternative that takes advantage of a type I am calling a MappingEnumerable. Take a look at the code for the class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MappingEnumerable<Input, Output> : IMappingEnumerable<Input, Output>
{
    private IMapper<Input, Output> mapper;
    private IEnumerable<Input> inputItems;


    public MappingEnumerable(IMapper<Input, Output> mapper, IEnumerable<Input> inputItems)
    {
        this.mapper = mapper;
        this.inputItems = inputItems;
    }


    IEnumerator<Output> IEnumerable<Output>.GetEnumerator()
    {
        return MapAllFrom(inputItems).GetEnumerator();
    }

    public IEnumerator GetEnumerator()
    {
        return ((IEnumerable<Output>) this).GetEnumerator();
    }

    private IEnumerable<Output> MapAllFrom(IEnumerable<Input> input)
    {
        foreach (Input item in input)
        {
            yield return mapper.MapFrom(item);
        }
    }
}

Using this class from the service layer is as simple as:

1
2
3
4
5
6
7
8
9
10
public IEnumerable<DepartmentDisplayItemDO> GetAllSubdepartmentsOf(long departmentId)
{
    IDepartment parentDepartment = departmentRepository.FindBy(departmentId);
    IEnumerable<IDepartment> subdepartments = departmentRepository.AllSubDepartmentsOf(parentDepartment);
    return
        new MappingEnumerable<IDepartment, DepartmentDisplayItemDO>
            (subdepartments,
             departmentDisplayItemDTOMapper);

}

Notice that the MappingEnumerable decorates the existing enumerable with mapping behaviour. Because the MappingEnumerable is itself an implementation of an IEnumerable interface, the mapping of each item will not start until the iteration of the enumerable happens.

Taking this class and applying it in the 3.5 world (I prefer using components vs free floating extension methods) can result in the following:

1
2
3
 IDepartment parentDepartment = departmentRepository.FindBy(departmentId);
 IEnumerable<IDepartment> subdepartments = departmentRepository.AllSubDepartmentsOf(parentDepartment);
 return subdepartments.MapAllUsing(departmentDisplayItemDTOMapper);

Where MapAllUsing is an extension method on IEnumerable which lives in my infrastructure layer. The simplified implementation of MapAllUsing just delegates the work to the MappingEnumerable class:

1
2
3
4
public static IEnumerable<Output> MapAllUsing<T,Output>(this IEnumerable<T> itemsToMap,IMapper<T,Output> mapper)
{
  return new MappingEnumerable<T, Output> (mapper,itemsToMap);
}

One more short example to show how I leverage this pattern in my apps take a look at this method on a DatabaseGateway interface:

1
IEnumerable<DataRow> GetASetOfRowsUsingA(IQuery query);

A simple method to return an enumerable of DataRows. You can now leverage this to do things like:

1
2
3
4
public IEnumerable<DomainObject> GetAllUsing(IQuery query)
{
   return gateway.GetASetOfRowsUsingA(query).MapAllUsing(dbMapper);
}

Where the mapper in this case knows how to hydrate datarows into domain objects of the specific (DomainObject) type the mapper is defined for.

One of the things I tell people in class (and work) is that IEnumerable is the ultimate Separated Interface and this post just scratches the surface of the things you can do by just getting creative with the IEnumerable interface.

Develop With Passion!!

Comments