AutoMapper - отображение производных классов без абстрактного класса на стороне источника - PullRequest
1 голос
/ 16 декабря 2010

Я пытаюсь отобразить следующий сценарий:

// SourceA + SourceB to not derive from a shared base class.
class SourceCollection
{
    IList<SourceA> ACollection;
    IList<SourceB> BCollection;

    // ... other properties ...
}

class DestCollection
{
    IList<DestBase> Collection;

    // ... other properties ...
}

abstract class DestBase { }

// In their destination form, DestA + DestB share DestBase as a base class.
class DestA : DestBase { }
class DestB : DestBase { }

Когда я сопоставляю SourceCollection> DestCollection, я хочу, чтобы каждая из коллекций была собрана в одну коллекцию. В идеале я хотел бы сделать это без специального распознавателя, поскольку AutoMapper прекрасно понимает, как правильно сопоставить SourceA> DestA и SourceB> DestB. Мне просто нужно понять, что SourceA может отображаться на DestBase как DestA, поскольку DestA происходит от DestBase.

Поскольку нет SourceBase, я не могу просто сопоставить это с DestBase и использовать .Include.

Я предполагаю, что для этого может потребоваться настраиваемый распознаватель, поскольку это две коллекции, объединяющиеся в одну (я бы просто ожидал, что результат будет объединен), но было бы неплохо, если бы он не требовал этого. Или, по крайней мере, я мог бы написать один пользовательский распознаватель, который был бы достаточно универсальным, чтобы его не нужно было менять, если появился SourceC + DestC.

Обновление:

Это ValueResolver, с которым он может быть достигнут, однако он требует учета каждого типа для разрешения вручную:

public class BaseCollectionResolver : ValueResolver< SourceCollection, IList<DestBase> >
{
    protected override IList<DestBase> ResolveCore(SourceCollection source)
    {
        var items = new List<DestBase>();

        foreach (var sourceA in source.ACollection)
            items.Add( Mapper.Map<SourceA, DestA>(sourceA) );

        foreach (var sourceB in source.BCollection)
            items.Add( Mapper.Map<SourceB, DestB>(sourceB) );

        return items;
    }
}

И затем отображается соответственно:

Mapper.CreateMap<SourceCollection, DestCollection>()
      .ForMember(dest => dest.Collection, m => m.ResolveUsing<BaseCollectionResolver>());

1 Ответ

1 голос
/ 16 декабря 2010

Я не могу придумать хороший способ сделать это без использования ITypeConverter:

public class SourceCollectionToDestCollection 
    : ITypeConverter<SourceCollection, DestCollection>
{
    public DestCollection Convert(ResolutionContext context)
    {
        SourceCollection source = context.SourceValue as SourceCollection;

        DestCollection destination = context.DestinationValue as DestCollection 
            ?? new DestCollection();

        foreach (var sourceA in source.ACollection)
        {
            DestA dest = Mapper.Map<SourceA, DestA>(sourceA);
            destination.Collection.Add(dest);
        }

        foreach (var sourceB in source.BCollection)
        {
            DestB dest = Mapper.Map<SourceB, DestB>(sourceB);
            destination.Collection.Add(dest);
        }

        return destination;
    }
}

И добавьте его в маппер:

Mapper.CreateMap<SourceCollection, DestCollection>()
    .ConvertUsing<SourceCollectionToDestCollection>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...