Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automapper automatically resolve correct subclass to map to?

Given the following source types:

public class BaseViewModel
{
   public string Prop1 { get; set; }
}

public class FirstViewModelImpl : BaseViewModel
{
   public string Prop2 { get; set; } 
}

public class SecondViewModelImpl : BaseViewModel
{
   public string AnotherProp { get; set; }
}

And the following destination types

public class BaseDto
{
   public string Prop1 { get; set; }
}

public class FirstDtoImpl : BaseDto
{
   public string Prop2 { get; set; } 
}

public class SecondDtoImpl : BaseViewModel
{
   public string AnotherProp { get; set; }
}

With the following mappings:

Mapper.CreateMap<FirstViewModelImpl,FirstDtoImpl>();
Mapper.CreateMap<SecondViewModelImpl,SecondDtoImpl>();

Can I do the following (trivial example) - given that I don't actually know the type of viewmodel until runtime?

BaseViewModel myViewModel = GetAViewModelFromSomewhere();
FirstDtoImpl dto = (FirstDtoImpl)Mapper.Map<BaseViewModel,BaseDto>(myViewModel);

I am trying this out now anyway!

like image 938
Rob Stevenson-Leggett Avatar asked Apr 28 '11 13:04

Rob Stevenson-Leggett


People also ask

Can AutoMapper map collections?

AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.

How does AutoMapper work in C#?

AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.

What can I use instead of AutoMapper?

Mapster is an emerging alternative to AutoMapper which was first published in 2015 and has over 7.4 million NuGet package downloads.


2 Answers

You can't do that directly, however you can work around it with a TypeConverter.

In the Mappings you will add:

Mapper.CreateMap<BaseViewModel, BaseDto>()
    .ConvertUsing<MyTypeConverter>();

Then you can create the converter like so:

public class MyTypeConverter : TypeConverter<BaseViewModel, BaseDto>
{
    protected override BaseDto ConvertCore(BaseViewModel tViewModel)
    {
        BaseDto vResult = null;
        if(tViewModel is FirstViewModelImpl)
        {
            var vSource = tViewModel as FirstViewModelImpl;
            vResult = Mapper.Map<FirstViewModelImpl,FirstDtoImpl>(vSource);
        }
        else if(tViewModel is SecondViewModelImpl )
        {
            var vSource = tViewModel as SecondViewModelImpl ;
            vResult = Mapper.Map<SecondViewModelImpl ,SecondDtoImpl>(vSource);
        }
        return vResult;
    }
}

Then you can use it like:

BaseDto dto= Mapper.Map<BaseViewModel,BaseDto>(myViewModel);

and have dto actually be of the type you wanted.

It won't map the Base types to each other though. If that matters I can twist it a bit more.

like image 199
Rangoric Avatar answered Oct 06 '22 04:10

Rangoric


I have found that if I change the mappings to

Mapper.CreateMap<BaseViewModel,BaseDto>()
        .Include<FirstViewModelImpl,FirstDtoImpl>()
        .Include<SecondViewModelImpl,SecondDtoImpl>();

Mapper.CreateMap<FirstViewModelImpl,FirstDtoImpl>();
Mapper.CreateMap<SecondViewModelImpl,SecondDtoImpl>();

Then it works as expected without using the type converter.

like image 26
Rob Stevenson-Leggett Avatar answered Oct 06 '22 05:10

Rob Stevenson-Leggett