If you use this IMapper<,> interface for all mappings
public interface IMapper<in TInput, out TOutput>
{
TOutput Map(TInput input);
}
It is immediately clear from what type to what type it maps. On top of that we can now create extension methods working for all mappers supporting this interface.>
This is what an ordinairy mapper would look like.
public class ProductMapper : IMapper<ProductDb, Product>
{
public Product Map(ProductDb input)
{
return new Product
{
OrderId = input.OrderId,
Name = input.FullName,
Price = input.PriceInCents * 100
};
}
}
public class OrderMapper : IMapper<OrderDB, Order>
{
private readonly IMapper<ProductDb, Product> _productmapper;
public OrderMapper(IMapper<ProductDb, Product> productmapper)
{
_productmapper = productmapper;
}
public Order Map(OrderDB input)
{
return new Order
{
OrderId = input.OrderId,
Products = input.Products.Select(p => _productmapper.Map(p)).ToList() // This is where this blog is about
};
}
}
With the extensions of IMapper<,> you can do a lot, but these a a few examples:
// This what you can do even with a custom non generic mapper interface
Products = input.Products.Select(p => _productmapper.Map(p)).ToList();
Products = input.Products.Select(_productmapper.Map).ToList();
// With some handy Extensions on Imapper, you can also
// write it this way without changing the ProductMapper
Products = _productmapper.Map(input.Products).ToList();
Products = _productmapper.MapToList(input.Products);
// Or when you want to start with the input like the other fields
Products = input.Products.Map(_productmapper).ToList();
Products = input.Products.MapToList(_productmapper);
Note: There are also async extensions and options for MampMany().
public static class MapperExtensions
{
public static IEnumerable<TOut> Map<TIn, TOut>(this IMapper<TIn, TOut> mapper, IEnumerable<TIn> values)
{
return values.Select(mapper.Map);
}
public static IEnumerable<TOut> Map<TIn, TOut>(this IEnumerable<TIn> values, IMapper<TIn, TOut> mapper)
{
return values.Select(mapper.Map);
}
public static TOut Map<TIn, TOut>(this TIn input, IMapper<TIn, TOut> mapper)
{
return mapper.Map(input);
}
public static List<TOut> MapToList<TIn, TOut>(this IMapper<TIn, TOut> mapper, IEnumerable<TIn> values)
{
return values.Map(mapper).ToList();
}
public static List<TOut> MapToList<TIn, TOut>(this IEnumerable<TIn> values, IMapper<TIn, TOut> mapper)
{
return values.Map(mapper).ToList();
}
public static IReadOnlyList<TOut> MapToReadOnlyList<TIn, TOut>(this IMapper<TIn, TOut> mapper, IEnumerable<TIn> values)
{
return values.MapToList(mapper);
}
public static IReadOnlyList<TOut> MapToReadOnlyList<TIn, TOut>(this IEnumerable<TIn> values, IMapper<TIn, TOut> mapper)
{
return values.MapToList(mapper);
}
public static async Task<IEnumerable<TOut>> Map<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<IEnumerable<TIn>> valuesTask)
{
var values = await valuesTask;
return mapper.Map(values);
}
public static async Task<IEnumerable<TOut>> Map<TIn, TOut>(this Task<IEnumerable<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return await mapper.Map(valuesTask);
}
public static async Task<TOut> Map<TIn, TOut>(this Task<TIn> inputTask, IMapper<TIn, TOut> mapper)
{
var input = await inputTask;
return mapper.Map(input);
}
public static async Task<TOut> Map<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<TIn> inputTask)
{
return await inputTask.Map(mapper);
}
public static async Task<List<TOut>> MapToList<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<IEnumerable<TIn>> valuesTask)
{
return (await valuesTask.Map(mapper)).ToList();
}
public static async Task<List<TOut>> MapToList<TIn, TOut>(this Task<IEnumerable<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return await MapToList(mapper, valuesTask);
}
public static async Task<List<TOut>> MapToReadOnlyList<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<IEnumerable<TIn>> valuesTask)
{
return await valuesTask.MapToList(mapper);
}
public static async Task<List<TOut>> MapToReadOnlyList<TIn, TOut>(this Task<IEnumerable<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return await valuesTask.MapToList(mapper);
}
public static async Task<List<TOut>> MapToList<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<List<TIn>> valuesTask)
{
return (await valuesTask).MapToList(mapper);
}
public static async Task<List<TOut>> MapToList<TIn, TOut>(this Task<List<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return (await valuesTask).MapToList(mapper);
}
public static async Task<IReadOnlyList<TOut>> MapToReadOnlyList<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<List<TIn>> valuesTask)
{
return (await valuesTask).MapToList(mapper);
}
public static async Task<IReadOnlyList<TOut>> MapToReadOnlyList<TIn, TOut>(this Task<List<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return (await valuesTask).MapToList(mapper);
}
public static async Task<IReadOnlyList<TOut>> MapToReadOnlyList<TIn, TOut>(this IMapper<TIn, TOut> mapper, Task<IReadOnlyList<TIn>> valuesTask)
{
return (await valuesTask).MapToList(mapper);
}
public static async Task<IReadOnlyList<TOut>> MapToReadOnlyList<TIn, TOut>(this Task<IReadOnlyList<TIn>> valuesTask, IMapper<TIn, TOut> mapper)
{
return (await valuesTask).MapToList(mapper);
}
public static IEnumerable<TOut> MapMany<TIn, TOut>(this IMapper<TIn, IEnumerable<TOut>> mapper, IEnumerable<TIn> values)
{
return values.SelectMany(mapper.Map);
}
public static IEnumerable<TOut> MapMany<TIn, TOut>(this IEnumerable<TIn> values, IMapper<TIn, IEnumerable<TOut>> mapper)
{
return values.SelectMany(mapper.Map);
}
public static IEnumerable<TOut> MapManyToList<TIn, TOut>(this IMapper<TIn, IEnumerable<TOut>> mapper, IEnumerable<TIn> values)
{
return values.SelectMany(mapper.Map).ToList();
}
public static IEnumerable<TOut> MapManyToList<TIn, TOut>(this IEnumerable<TIn> values, IMapper<TIn, IEnumerable<TOut>> mapper)
{
return values.SelectMany(mapper.Map).ToList();
}
}
public class Order
{
public Guid OrderId { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public Guid OrderId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class OrderDB
{
public Guid OrderId { get; set; }
public List<ProductDb> Products { get; set; }
}
public class ProductDb
{
public Guid OrderId { get; set; }
public string FullName { get; set; }
public int PriceInCents { get; set; }
}