IMapper<in TInput, out TOutput> interface with handy extensions

1 interface for all mappings with handy extension methods!

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.>

Example ordinary mapper

This is how 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
        };
    }
}

Using the extensions

With the extensions of IMapper<,> you can do a lot, but these are 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);

The extensions source

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

Classes used in example.


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

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

Leave a Comment

Comment

Comments