У меня есть требование отобразить один объект в список объектов.Я делаю это с помощью автоматического преобразователя типов.
Отображаемые объекты являются частью двух иерархий наследования, и моя цель состоит в том, чтобы уменьшить количество повторяющихся конфигураций сопоставления, которые мне в настоящее время необходимо явно указать.
Ниже приведен пример сокращенного кода.Я упростил условие проекции списка для краткости.
Иерархии наследования:
public class BaseA {
public Guid Id1 { get; set; } = Guid.NewGuid();
}
public class BaseB {
public Guid Id2 { get; set; } = Guid.NewGuid();
}
public class DerivedA : BaseA {
}
public class DerivedB : BaseB {
}
Преобразователь типов:
public class BaseAToBaseBConverter<TBaseA, TBaseB> : ITypeConverter<TBaseA, List<TBaseB>>
where TBaseA : BaseA
where TBaseB : BaseB
{
public List<TBaseB> Convert(TBaseA source, List<TBaseB> destination, ResolutionContext context) {
if (destination == null) {
destination = new List<TBaseB>();
}
for (var i = 0; i < (int) context.Items["InstancesToCreate"]; i++) {
destination.Add(context.Mapper.Map<TBaseA, TBaseB>(source));
}
return destination;
}
}
Профиль отображения:
public class MappingProfile : Profile {
public MappingProfile() {
CreateMap<BaseA, BaseB>()
.ForMember(destination => destination.Id2, o => o.MapFrom(source => source.Id1))
.IncludeAllDerived();
CreateMap<BaseA, List<BaseB>>().ConvertUsing<BaseAToBaseBConverter<BaseA, BaseB>>();
CreateMap<DerivedA, DerivedB>();
CreateMap<DerivedA, List<DerivedB>>().ConvertUsing<BaseAToBaseBConverter<DerivedA, DerivedB>>();
}
}
Тесты:
private IMapper _mapper;
[SetUp]
public void SetUp() {
_mapper = new MapperConfiguration(mc => {
mc.AddProfile<MappingProfile>();
}).CreateMapper();
}
[Test]
public void Map_SingleBaseAToList_ReturnsList() {
var baseA = new BaseA();
var baseB = _mapper.Map<BaseA, List<BaseB>>(baseA, options => options.Items["InstancesToCreate"] = 2);
Assert.Multiple(() =>
{
Assert.That(baseB.Count, Is.EqualTo(2));
Assert.That(baseB.Select(x => x.Id2).Distinct().Single(), Is.EqualTo(baseA.Id1));
});
}
[Test]
public void Map_SingleDerivedBaseAToList_ReturnsList() {
var derivedA = new DerivedA();
var derivedB = _mapper.Map<DerivedA, List<DerivedB>>(derivedA, options => options.Items["InstancesToCreate"] = 2);
Assert.Multiple(() => {
Assert.That(derivedB.Count, Is.EqualTo(2));
Assert.That(derivedB.Select(x => x.Id2).Distinct().Single(), Is.EqualTo(derivedA.Id1));
});
}
Вышеприведенное работает отлично.Однако в действительности BaseA и BaseB являются абстрактными классами с кучей производных объектов, свисающих с них.Это означает, что я получаю достаточно длинный и очень повторяющийся профиль отображения.Я хотел бы знать, есть ли какой-то способ указать один ConvertUsing
для единственного списка в базовых типах, и чтобы производные типы использовали это определение, как мы можем для отображения типа на тип.Что-то вроде следующего:
CreateMap<BaseA, BaseB>()
.ForMember(destination => destination.Id2, o => o.MapFrom(source => source.Id1))
.IncludeAllDerived();
CreateMap<BaseA, List<BaseB>>()
.ConvertUsing<BaseAToBaseBConverter<BaseA, BaseB>>()
.IncludeAllDerived();
CreateMap<DerivedA, DerivedB>();
CreateMap<DerivedA, List<DerivedB>>();
Это недопустимо, поскольку нет прямого преобразования между List<BaseB>
и List<DerivedB>
.Есть ли другой способ заставить отображения работать так?