Может ли AutoMapper создать карту для интерфейса, а затем сопоставить с производным типом? - PullRequest
2 голосов
/ 26 декабря 2010

У меня есть интерфейс IFoo:

public interface IFoo
{
    int Id { get; set; }
}

А затем конкретная реализация:

public class Bar : IFoo
{
    public int Id { get; set; }
    public string A { get; set; }
}

public class Baz : IFoo
{
    public int Id { get; set; }
    public string B { get; set; }
}

Я бы хотел иметь возможность отобразить все IFoo, но указав вместо этого их производный тип:

Mapper.CreateMap<int, IFoo>().AfterMap((id, foo) => foo.Id = id);

И затем сопоставьте (без явного создания карт для Bar и Baz):

var bar = Mapper.Map<int, Bar>(123);
// bar.Id == 123

var baz = Mapper.Map<int, Baz>(456);
// baz.Id == 456

Но в 1.1 это не работаетЯ знаю, что могу указать all Bar и Baz, но если их 20, мне бы не пришлось управлять ими, а просто иметь то, что я делал выше для создания карты.Это возможно?

1 Ответ

2 голосов
/ 27 декабря 2010

Я нашел решение этой проблемы. Я создал реализацию IObjectMapper:

// In this code IIdentifiable would be the same as IFoo in the original post.

public class IdentifiableMapper : IObjectMapper
{
    public bool IsMatch(ResolutionContext context)
    {
        var intType = typeof(int);
        var identifiableType = typeof(IIdentifiable);

        // Either the source is an int and the destination is an identifiable.
        // Or the source is an identifiable and the destination is an int.
        var result = (identifiableType.IsAssignableFrom(context.DestinationType) && intType == context.SourceType) || (identifiableType.IsAssignableFrom(context.SourceType) && intType == context.DestinationType);
        return result;
    }

    public object Map(ResolutionContext context, IMappingEngineRunner mapper)
    {
        // If source is int, create an identifiable for the destination.
        // Otherwise, get the Id of the identifiable.
        if (typeof(int) == context.SourceType)
        {
            var identifiable = (IIdentifiable)mapper.CreateObject(context);
            identifiable.Id = (int)context.SourceValue;
            return identifiable;
        }
        else
        {
            return ((IIdentifiable)context.SourceValue).Id;
        }
    }
}

Это здорово, но его нужно зарегистрировать в реестре картографа. Он должен идти в начале списка, так как мы хотим перехватить все int/IIdentifiable комбинации источника и назначения (это находится в конфигурации, такой как Global.asax):

var allMappers = MapperRegistry.AllMappers();

MapperRegistry.AllMappers = () => new IObjectMapper[]
{
    new IdentifiableMapper(),
}.Concat(allMappers);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...