Search code examples
genericsautomapperopen-generics

Automapper and Open Generics


I'm trying to use Automapper's Open Generics as described in https://github.com/AutoMapper/AutoMapper/wiki/Open-Generics to perform a mapping between User and Account.

public class User
{
    public Guid UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime Dob { get; set; }
}

public class Account
{
    public Guid UserId { get; set; }
    public string FirstName { get; set; }
}

I created the Source and Destination

public class Source<T>
{
    public T Value { get; set; }
}

public class Destination<T>
{
    public T Value { get; set; }
}

I want to perform the mapping in an AccountService

public class AccountService
{
    private User user1 = new User{FirstName = "James", LastName = "Jones", Dob = DateTime.Today, UserId = new Guid("AC482E99-1739-46FE-98B8-8758833EB0D2")};

    static AccountService()
    {
        Mapper.CreateMap(typeof(Source<>), typeof(Destination<>));
    }

    public T GetAccountFromUser<T>()
    {
        var source = new Source<User>{ Value = user1 };
        var destination = Mapper.Map<Source<User>, Destination<T>>(source);
        return destination.Value;
    }
}

But I get an exception

Missing type map configuration or unsupported mapping.

Mapping types: User -> Account OpenGenerics.Console.Models.User -> OpenGenerics.Console.Models.Account

Destination path: Destination`1.Value.Value

Source value: OpenGenerics.Console.Models.User

I confirmed the approach in https://github.com/AutoMapper/AutoMapper/wiki/Open-Generics works for int and double

Edit This might be a solution for me, it's a little messy though.

    var mappingExists = Mapper.GetAllTypeMaps().FirstOrDefault(m => m.SourceType == typeof (User) && m.DestinationType == typeof (T));
    if (mappingExists == null)
        Mapper.CreateMap<User, T>();

Solution

  • For closed generics, the type parameters also need to be able to be mapped. Add this:

    Mapper.CreateMap<User, Account>();
    

    And you're set.