简体   繁体   中英

Map to specific derived type based on value on source using Automapper

I'm having trouble implementing Automapper conversion in a situation where the source is a class which should be mapped to one of two derived classes based on a value on the source.

Here's a simplification of my classes:

public class FooContainerDTO
{
    public FooDTO Foo { get; set; } 
}

public class FooDTO
{
    public string Type { get; set; }

    //some properties..
}

public class FooContainer
{
    public FooBase Foo { get; set; }
}

public abastract class FooBase
{
    //some properties..
}

public class FooDerived1 : FooBase
{
    //some properties
}

public class FooDerived2 : FooBase
{
    //some properties
}

I'm using non-static Automapper so I create a MapperConfiguration from several Profiles at boot and inject the IMapper instance into my DI-container. I want Automapper to map FooDTO to FooDerived1 when its Type property is "der1" and to FooDerived2 when it is "der2".

I've seen examples on this using the static api, something like this:

 Mapper.CreateMap<FooContainerDTO, FooContainer>();
        //ForMember configurations etc.

 Mapper.CreateMap<FooDTO, FooDerived1>();
        //ForMember configurations etc.

 Mapper.CreateMap<FooDTO, FooDerived2>();
        //ForMember configurations etc.

 Mapper.CreateMap<FooDTO, FooBase>()
       .ConvertUsing(dto => dto.Type == "der1"
           ? (FooBase) Mapper.Map<FooDerived1>(dto)
           : Mapper.Map<FooDerived2>(dto));

This would map the Foo property of FooContainer to the correct derived type of FooBase.

But how can I do this without the static API? The IMapper instance is not yet created at the point of configuring the profile. Is there a way to leverage the overload of ConvertUsing() which takes a Func< ResolutionContext,object >? Can the resolution context give me whatever IMapper is currently being used? I've been looking, but can't find anything usable.

One way to get access to the mapping engine is via your own TypeConverter

abstract class MyTypeConverter<TSource,TDestination> : ITypeConverter<TSource, TDestination>
{
    protected ResolutionContext context;
    public TDestination Convert(ResolutionContext context)
    {
        this.context = context;
        return Convert((TSource)context.SourceValue);
    }
    public abstract TDestination Convert(TSource source);
}

You then create an actual implementation like:

class MyTypeMapper : MyTypeConverter<EnumType,EnumTypeView>
{
    public override EnumTypeView Convert(EnumType source)
    {
        return context.Engine.Mapper.Map<EnumTypeID, EnumTypeView>(source.EnumBaseType);
    }
}

Except instead of unwrapping an enum structure, you'd check the type and call Map with different types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM