Question

I've just started with AutoMapper in C#. I've succesfully created a mapping like this:

Mapper.CreateMap<InputTypeA, OutputTypeA>()

I've also found a way to add some logic to specific properties, like formatting a date (in InputTypeA) to a string in a specific format (in OutputTypeA).

.ForMember(
    dest => dest.MyDateProperty,
    opt => opt.ResolveUsing(
        src => String.Format("{0:yyyy-MM-dd}", src.MyDateProperty)));

Now I need to do the same for a number of float properties, but I'm wondering if there is a short/easy way to do this, except copying a piece of code like the one above for every property that needs to follow this rule.

I've found that I can create a new map like this for mapping floats to strings:

Mapper.CreateMap<float,string>()
    .ConvertUsing(src =>
        String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:0.00}", src));

This works, but is too generic, because I also have a mapping for another type (let's call it InputTypeB), that also contains float properties, which need to be treated differently.

Mapper.CreateMap<InputTypeB, OutputTypeB>()

How can I make the float-to-string mapping part of the first mapping only?

Was it helpful?

Solution

You could create two separate mappers based on two separate configurations, only one of which includes the float-to-string mapping:

public class InputTypeA { public float Foo { get; set; } }

public class OutputTypeA { public string Foo { get; set; } }

public class InputTypeB { public float Bar { get; set; } }

public class OutputTypeB { public string Bar { get; set; } }

public class Program
{
    public static void Main(string[] args)
    {
        Func<float, string> mapFunc =
            src => String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:0.00}", src);

        var floatToStringConfig = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<InputTypeA, OutputTypeA>();
            cfg.CreateMap<float, string>().ConvertUsing(mapFunc);
        });

        var regularConfig = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<InputTypeB, OutputTypeB>();
        });

        IMapper floatToStringMapper = floatToStringConfig.CreateMapper();
        IMapper regularMapper = regularConfig.CreateMapper();

        var aIn = new InputTypeA() { Foo = 1f };
        var aOut = floatToStringMapper.Map<OutputTypeA>(aIn); 

        Console.WriteLine(aOut.Foo); // prints "1.00"

        var bIn = new InputTypeB() { Bar = 1f };
        var bOut = regularMapper.Map<OutputTypeB>(bIn);

        Console.WriteLine(bOut.Bar); // prints "1"
    }
}

OTHER TIPS

You can create custom value resolvers for each case you need to handle. Then apply these to the appropriate members in your mappings.

As an example, I need to map from TypeA to TypeB, I only want DateB to use the custom conversion:

 public class TypeA {
    public DateTime DateA { get; set; } 
    public DateTime DateB { get; set; }
}

public class TypeB {
    public string DateA { get; set; }
    public string DateB { get; set; }
}

I create a custom resolver:

 class DateStringResolver : ValueResolver<DateTime, string> {
     protected override string ResolveCore(DateTime source) {
         return String.Format("{0:yyyy-MM-dd}", source);
     }
 }

Then in my mapper config:

                 Mapper.CreateMap<TypeA, TypeB>()
                 //Only Date B will use our custom resolver
                 .ForMember(d => d.DateB, opt => opt.ResolveUsing<DateStringResolver>().FromMember(src => src.DateA));

The resolver can now be applied wherever it is needed.

Docs:https://github.com/AutoMapper/AutoMapper/wiki/Custom-value-resolvers

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top