我正在尝试在两个对象列表之间进行映射。源类型具有类型A
的复杂属性;目标类型是类型A
的展平子集以及源类型中的其他标量属性。
public class A
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Source
{
public A MyA { get; set; }
public int SomeOtherValue { get; set; }
}
public class Destination
{
public string Name { get; set; }
public int SomeOtherValue { get; set; }
}
如果不清楚,我希望Source.MyA.Name
映射到Destination.Name
和Source.SomeOtherValue
以映射到Destination.SomeOtherValue
。
实际上,类型A
有十几个属性,其中80%映射到Destination
中同名属性。如果我明确地在CreateMap
中详细说明映射,我可以让事情发挥作用:
CreateMap<Source, Destination>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.MyA.Name));
这里的缺点是我希望避免为每个需要复制到ForMember
的{{1}}属性添加A
行。我希望我能做一些像:
Destination
但如果我尝试上述操作,则在注册映射时会出现运行时错误:“仅对类型上的顶级个人成员支持成员的自定义配置。”
由于
答案 0 :(得分:5)
在A
和Destination
以及Source
和Destination
之间创建映射,然后使用AfterMap()
在第二个中使用第一个映射
Mapper.CreateMap<A, Destination>();
Mapper.CreateMap<Source, Destination>()
.AfterMap((s, d) => Mapper.Map<A, Destination>(s.MyA, d));
然后像这样使用它:
var res = Mapper.Map<Source, Destination>(new Source { SomeOtherValue = 7, MyA = new A { Id = 1, Name = "SomeName" } });
答案 1 :(得分:0)
作为一种解决方法,您可以在目标类型中使用带有附加属性的自定义类型转换器,以避免递归。
[TestFixture]
public class MapComplexType
{
[Test]
public void Map()
{
Mapper.CreateMap<A, Destination>();
Mapper.CreateMap<Source, Destination>().ConvertUsing(new TypeConvertor());
var source = new Source
{
MyA = new A
{
Name = "Name"
},
SomeOtherValue = 5
};
var dest = new Destination();
Mapper.Map(source, dest);
Assert.AreEqual(dest.Name, "Name");
}
}
public class TypeConvertor : ITypeConverter<Source, Destination>
{
public Destination Convert(ResolutionContext context)
{
var destination = (Destination) context.DestinationValue;
if (!((Destination)context.DestinationValue).IsMapped || destination == null)
{
destination = destination ?? new Destination();
destination.IsMapped = true; // To avoid recursion
Mapper.Map((Source)context.SourceValue, destination);
destination.IsMapped = false; // If you want to map the same object few times
}
Mapper.Map(((Source)context.SourceValue).MyA, destination);
return (Destination)context.DestinationValue;
}
}
public class A
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Source
{
public A MyA { get; set; }
public int SomeOtherValue { get; set; }
}
public class Destination
{
public string Name { get; set; }
public int SomeOtherValue { get; set; }
// Used only for mapping purposes
internal bool IsMapped { get; set; }
}
答案 2 :(得分:0)
试试这个,
Mapper.CreateMap<A, Destination>();
Mapper.CreateMap<Source, Destination>()
.ForMember(destination => destination.Name, options => options.MapFrom(source => Mapper.Map<A, Destination>(source.MyA).Name));
var objSource = new Source { SomeOtherValue = 7, MyA = new A { Id = 1, Name = "SomeName" } };
var result = Mapper.Map<Source, Destination>(objSource);