Enhancing mappers with LINQ

The “big 3″ higher-order functions in functional programming are Filter, Map and Reduce.  When looking at the new C# 3.0 LINQ query operators, we find that all three have equivalents:

  • Filter = Where
  • Map = Select
  • Reduce = Aggregate

Whenever you find yourself needing one of these three higher-order functions, just translate them into the correct query operator.  “Select” doesn’t have the same dictionary meaning as “Map”, but the signature is exactly the same.

The trick to knowing you can use these higher order functions is to look out for situations where you:

  1. Create a new collection
  2. Iterate through some other collection
  3. Add items from the other collection to the new collection

Any time you see this general algorithm, there’s a much terser syntax available with LINQ.

Mapper patter example

For example, consider the Mapper pattern:

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

A common scenario to map is when I’m creating DTOs or message objects from Domain objects.  Serializing domain objects generally isn’t a concern of the domain object, as DTOs tend to be flattened out somewhat.  I might have the following domain objects:

public class Customer
{
    public Guid Id  { get; set; }
    public string Name { get; set; }
}
public class SalesOrder
{
    public Customer Customer { get; set; }
    public decimal Total { get; set; }
}

I’d like to send a Sales Order over the wire for display in some client application.  But suppose the Customer object contains dozens of properties, perhaps things like a billing address, a shipping address, and so on.  The service I’m creating only needs a summary of customer information, so I create a SalesOrderSummary message class:

public class SalesOrderSummary
{
    public string CustomerName { get; private set; }
    public Guid CustomerId { get; private set; }
    public decimal Total { get; private set; }

    // For serialization
    private SalesOrderSummary() { }

    public SalesOrderSummary(string customerName, Guid customerId, decimal total)
    {
        CustomerName = customerName;
        CustomerId = customerId;
        Total = total;
    }
}

The corresponding mapper would look like:

public class SalesOrderSummaryMapper : IMapper<SalesOrder, SalesOrderSummary>
{
    public SalesOrderSummary Map(SalesOrder input)
    {
        return new SalesOrderSummary(input.Customer.Name, input.Customer.Id, input.Total);
    }
}

Nothing too exciting so far, right?  Well, suppose now I need to return an array of SalesOrderSummary, perhaps for display in a grid.  In that case, I’ll need to build up a list of SalesOrderSummary objects based on a list of SalesOrder objects:

public SalesOrderSummary[] FindSalesOrdersByMonth(DateTime date)
{
    // get the sales orders from the repository first
    IEnumerable<SalesOrder> salesOrders = GetSalesOrders();

    var salesOrderSummaries = new List<SalesOrderSummary>();
    var mapper = new SalesOrderSummaryMapper();

    foreach (var salesOrder in salesOrders)
    {
        salesOrderSummaries.Add(mapper.Map(salesOrder));
    }

    return salesOrderSummaries.ToArray();
}

This isn’t too bad, but the creation of a second list just to build up an array seems rather pointless.  But by borrowing some ideas from JP, we can make this a lot easier.

Using LINQ

We can already see the higher order function we need, it’s in the name of the mapper!  Instead of “Map”, we’ll use “Select” to do the transforming.  But since we have the interface, we can create an extension method to do the Map function:

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));
    }
}

This new MapAll function is the functional programming Map function, where it takes an input list and returns a new IEnumerable with the mapped values.  Internally, the Select LINQ query operator will loop through our input, calling the lambda function we passed in (mapper.Map).  This is the exact same operation in our original example, but now our service method now becomes much smaller:

public SalesOrderSummary[] FindSalesOrdersByMonth(DateTime date)
{
    // get the sales orders from the repository first
    IEnumerable<SalesOrder> salesOrders = GetSalesOrders();
    var mapper = new SalesOrderSummaryMapper();

    return mapper.MapAll(salesOrders).ToArray();
}

Much nicer, our service method is reduced to just a handful of lines.  The nice thing about this syntax is that it removes all of the unnecessary cruft of a temporary list creation that clouded the intent of this method.

So any time you find yourself creating a temporary list just to build up some filtered, mapped or reduced values, stop yourself.  There’s a higher calling available with functional programming and LINQ.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in C#, Domain-Driven Design, LINQ. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://neilmosafi.blogspot.com Neil Mosafi

    That is nice, but you could have avoided the creation of the extra list without using LINQ, by yielding, as follows:

    public static IEnumerable MapAll(this IMapper mapper,
    IEnumerable
    input)
    {
    foreach (TInput x in input)
    yield return mapper.Map(x);
    }

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Neil

    You could definitely do that. But remember, the Select LINQ query operator does that for you as it has deferred query execution. The LINQ query operators use the yield operator all over the dang place.

  • http://colinjack.blogspot.com/ Colin Jack

    Good stuff, makes me wonder whether every codebase has an IMapper style interface.

  • http://www.elegantcode.com Jarod

    I prefer”
    GetSalesOrders()
    .Select(SalesOrderSummaryMapper.Map)
    .ToArray();

    Even less code and no extra extension method

  • Alexey Romanov

    Why would you prefer IMapper over
    delegate TOutput Map
    (TInput input)?

    And then notice that this delegate already exists in the framework (two times, yet!).

    The only thing I can suppose is that you want to have a name for a reused mapper. But in this case you can easily do

    public static class SalesOrderSummaryMapper {
    public static readonly Func Map =
    input => new SalesOrderSummary(input.Customer.Name, input.Customer.Id, input.Total;
    }

    or

    public static partial class Mappers {
    public static readonly Func SalesOrderSummaryMap =
    input => new SalesOrderSummary(input.Customer.Name, input.Customer.Id, input.Total;
    //other mappers
    }

  • Doug Koehn

    Using the System.Converter delegate.

    All you need is the following extension method:

    public static IEnumerable ConvertAll(this IEnumerable list, Converter converter)
    {
    foreach (TInput v in list)
    yield return converter.Invoke(v);
    }

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Alexey, Doug

    The problem with a delegate by itself is that it’s difficult to reuse. If I wanted to go that approach, I’d have two items: a method to perform the mapping, and the delegate field to point to the map method.

    I’ve done something similar with specifications, which was clever, but didn’t really lead to “intention-revealing interfaces”.

  • http://scottic.us Scott Bellware

    “IEnumerable MapAll(this IMapper mapper, IEnumerable input)”

    This looks like LoC optimization at the sake of solubility. Had to read that signature a couple of times to really assimilate it. I’d go back to the previous implementation. It’s cool and all, but to me, it’s merely cool.

  • http://colinjack.blogspot.com/ Colin Jack

    Slightly unrelated question, you’ve used the pattern I’ve tried:

    SalesOrderSummaryMapper : IMapper

    Just wondering though, do you inject mappers into each other, so if a particular mapper needs to use another mapper do you use constructor injection and if so do you just inject IMapper or a custom interface?

    Just interested in other peoples approaches really…

  • Dan Malcolm

    @Colin

    I would say (constructor) inject away!

    It simplifies the mapping code if mappers don’t have to think about instantiating other mappers.

    Also if you have a hierarchy of mappers, e.g. Product . Sku . SkuOffering, and the mapper at level 3 has a dependency on another service, it would be pretty horrible if the mapper at level 2 had to create the concrete service and pass it to the constructur of the level 3 mapper. You probably won’t have that many additional dependencies in a typical mapper, but you may want to separate out certain kinds of reusable functionality (perhaps something that needs flexible configuration) into a separate service.

    If you have some code that automatically registers the mappers in your IOC container at startup, then you’ve less code to maintain.

    Re. your second question, I have found it preferable to inject mappers as type IMapper, rather than by a more specialised interface. In one case, I had a mapper that could convert from 2 different types to the TOutput type and it implemented implemented IMapper< ,> twice, with different sets of generic parameters. I created a JP-style MapAll extension method on IEnumerable (non-generic). Referring to the IMapper< ,> interface, rather than the concrete mapper type, allowed the generic arguments to be inferred from the interface and the items in the input collection could be automatically cast to TInput by the extension method (this is a pretty obscure scerario now that I think about it, sorry!).

    HTH

    Dan