Value ConvertersΒΆ

Value converters are a cross between Type Converters and Value Resolvers. Type converters are globally scoped, so that any time you map from type Foo to type Bar in any mapping, the type converter will be used. Value converters are scoped to a single map, and receive the source and destination objects to resolve to a value to map to the destination member. Optionally value converters can receive the source member as well.

In simplified syntax:

  • Type converter = Func<TSource, TDestination, TDestination>
  • Value resolver = Func<TSource, TDestination, TDestinationMember>
  • Member value resolver = Func<TSource, TDestination, TSourceMember, TDestinationMember>
  • Value converter = Func<TSourceMember, TDestinationMember>

To configure a value converter, use at the member level:

public class CurrencyFormatter : IValueConverter<decimal, string> {
    public string Convert(decimal source)
        => source.ToString("c");
}

Mapper.Initialize(cfg => {
   cfg.CreateMap<Order, OrderDto>()
       .ForMember(d => d.Amount, opt => opt.ConvertUsing(new CurrencyFormatter()));
   cfg.CreateMap<OrderLineItem, OrderLineItemDto>()
       .ForMember(d => d.Total, opt => opt.ConvertUsing(new CurrencyFormatter()));
});

You can customize the source member when the source member name does not match:

public class CurrencyFormatter : IValueConverter<decimal, string> {
    public string Convert(decimal source)
        => source.ToString("c");
}

Mapper.Initialize(cfg => {
   cfg.CreateMap<Order, OrderDto>()
       .ForMember(d => d.Amount, opt => opt.ConvertUsing(new CurrencyFormatter(), src => src.OrderAmount));
   cfg.CreateMap<OrderLineItem, OrderLineItemDto>()
       .ForMember(d => d.Total, opt => opt.ConvertUsing(new CurrencyFormatter(), src => src.LITotal));
});

If you need the value converters instantiated by the service locator, you can specify the type instead:

public class CurrencyFormatter : IValueConverter<decimal, string> {
    public string Convert(decimal source)
        => source.ToString("c");
}

Mapper.Initialize(cfg => {
   cfg.CreateMap<Order, OrderDto>()
       .ForMember(d => d.Amount, opt => opt.ConvertUsing<CurrencyFormatter, decimal>());
   cfg.CreateMap<OrderLineItem, OrderLineItemDto>()
       .ForMember(d => d.Total, opt => opt.ConvertUsing<CurrencyFormatter, decimal>());
});

If you do not know the types or member names at runtime, use the various overloads that accept System.Type and string-based members:

public class CurrencyFormatter : IValueConverter<decimal, string> {
    public string Convert(decimal source)
        => source.ToString("c");
}

Mapper.Initialize(cfg => {
   cfg.CreateMap(typeof(Order), typeof(OrderDto))
       .ForMember("Amount", opt => opt.ConvertUsing(new CurrencyFormatter(), "OrderAmount"));
   cfg.CreateMap(typeof(OrderLineItem), typeof(OrderLineItemDto))
       .ForMember("Total", opt => opt.ConvertUsing(new CurrencyFormatter(), "LITotal"));
});

Value converters are only used for in-memory mapping execution. They will not work for ProjectTo.