简体   繁体   English

AutoMapper-在源端映射没有抽象类的派生类

[英]AutoMapper - Mapping derived classes without abstract class on source side

I am trying to map the following scenario: 我正在尝试映射以下情况:

// 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 { }

When I map SourceCollection > DestCollection I want each of the collections to be gathered into a single collection. 当我映射SourceCollection> DestCollection时,我希望将每个集合都收集到一个集合中。 Ideally I would like to do this without a custom resolver, since AutoMapper understands how to map SourceA > DestA and SourceB > DestB fine. 理想情况下,我想在没有自定义解析器的情况下执行此操作,因为AutoMapper可以很好地映射SourceA> DestA和SourceB> DestB。 I just need it to realise that SourceA can map to DestBase as DestA, as DestA derives from DestBase. 我只需要认识到SourceA可以作为DestA映射到DestBase,因为DestA是从DestBase派生的。

As there is no SourceBase I can't just map that to DestBase and use .Include. 由于没有SourceBase,因此我不能仅将其映射到DestBase并使用.Include。

I'm guessing this might require a custom resolver since it is two collections merging into one (I would just expect the result to be concatonated), but it would be nice if it didn't require it. 我猜想这可能需要一个自定义解析器,因为它将两个集合合并为一个(我只是希望结果被合并),但是如果不需要它会很好。 Or at least I could write a single custom resolver that was generic enough to not require to be changed if SourceC + DestC came along. 或者至少我可以编写一个通用的自定义解析器,如果出现SourceC + DestC,则不需要更改它。

Update: 更新:

This is a ValueResolver it can be achieved with, however it does require accounting for each type to resolve manually: 这是一个可以实现的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;
    }
}

And then mapped accordingly: 然后相应地映射:

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

I can't think of a nice way to do it without using an ITypeConverter : 我想不出一个不使用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;
    }
}

And add it to the mapper: 并将其添加到映射器:

Mapper.CreateMap<SourceCollection, DestCollection>()
    .ConvertUsing<SourceCollectionToDestCollection>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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