虽然AutoMapper已经提供了非常多的目标成员映射方案,但仍会有1%‑5%的目标值需要额外逻辑才能完成解析。很多时候,这类自定义值解析逻辑属于领域逻辑,可以直接放在领域对象上。但如果该逻辑仅用于映射场景,放到源类型中会污染源对象,产生不必要的行为。针对这类场景,AutoMapper支持为目标成员配置自定义值解析器。
例如,我们希望映射过程中得到一个计算后的结果:
public class Source
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}
public class Destination
{
public int Total { get; set; }
}Code language: JavaScript (javascript)
业务需求是让Total等于源对象两个Value属性相加。出于某些原因,我们不能也不应该把这段计算逻辑写在Source类型内部。想要使用自定义值解析器,首先需要创建一个实现IValueResolver接口的类:
public interface IValueResolver<in TSource, in TDestination, TDestMember>
{
TDestMember Resolve(TSource source, TDestination destination, TDestMember destMember, ResolutionContext context);
}Code language: PHP (php)
ResolutionContext包含本次解析的全部上下文信息,例如源类型、目标类型、源取值等。下面是接口的示例实现:
public class CustomResolver : IValueResolver<Source, Destination, int>
{
public int Resolve(Source source, Destination destination, int member, ResolutionContext context)
{
return source.Value1 + source.Value2;
}
}Code language: HTML, XML (xml)
完成IValueResolver实现类之后,需要告知AutoMapper在解析指定目标成员时使用该自定义解析器。一共有三种方式指定自定义值解析器:
MapFrom<TValueResolver>MapFrom(typeof(CustomValueResolver))MapFrom(aValueResolverInstance)
下面示例使用第一种泛型方式,直接指定解析器类型:
Mapper.Initialize(cfg =>
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total, opt => opt.MapFrom<CustomResolver>()));
Mapper.AssertConfigurationIsValid();
var source = new Source
{
Value1 = 5,
Value2 = 7
};
var result = Mapper.Map<Source, Destination>(source);
result.Total.ShouldEqual(12);Code language: JavaScript (javascript)
Previous: 投影(Projection)
Next: 空值替换