您的位置:首页 > 移动开发

AutoMapper官方文档(十二)【自定义值解析器】

2017-11-28 16:18 393 查看
尽管
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; }
}


无论出于何种原因,我们希望
Total
是源值属性的总和。 由于其他原因,我们不能或不应该把这个逻辑放在我们的
Source
类型上。为了提供自定义的值解析器,我们需要先创建一个实现
IValueResolver
的类型:

public interface IValueResolver<in TSource, in TDestination, TDestMember>
{
TDestMember Resolve(TSource source, TDestination destination, TDestMember destMember, ResolutionContext context);
}


ResolutionContext
包含当前解析操作的所有上下文信息,例如源类型,目标类型,源值等。 一个示例实现:

public class CustomResolver : IValueResolver<Source, Destination, int>
{
public int Resolve(Source source, Destination destination, int member, ResolutionContext context)
{
return source.Value1 + source.Value2;
}
}


一旦我们有了我们的
IValueResolver
实现,我们将需要告诉
AutoMapper
在解析特定的目标成员时使用这个自定义的值解析器。 我们有几个选项告诉
AutoMapper
一个自定义的值解析器使用,包括:

ResolveUsing<TValueResolver>
ResolveUsing(typeof(CustomValueResolver))
ResolveUsing(aValueResolverInstance)


在下面的例子中,我们将使用第一个选项,通过泛型告诉
AutoMapper
自定义的解析器类型:

Mapper.Initialize(cfg =>
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total, opt => opt.ResolveUsing<CustomResolver>());
Mapper.AssertConfigurationIsValid();

var source = new Source
{
Value1 = 5,
Value2 = 7
};

var result = Mapper.Map<Source, Destination>(source);

result.Total.ShouldEqual(12);


尽管目标成员(
Total
)没有任何匹配的源成员,但指定自定义解析程序使配置有效,因为解析程序现在负责为目标成员提供值。

如果我们不关心我们的值解析器中的源/目标类型,或者想要在映射上重用它们,我们可以使用
“object”
作为源/目标类型:

public class MultBy2Resolver : IValueResolver<object, object, int> {
public int Resolve(object source, object dest, int destMember, ResolutionContext context) {
return destMember * 2;
}
}


自定义构造函数方法

由于我们只将自定义解析器的类型提供给
AutoMapper
,所以映射引擎将使用反射来创建值解析器的实例。

如果我们不希望
AutoMapper
使用反射来创建实例,我们可以直接提供它:

Mapper.Initialize(cfg => cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total,
opt => opt.ResolveUsing(new CustomResolver())
);


AutoMapper
将使用该特定对象,在解析器可能具有构造函数参数或需要由IoC容器构造的场景中很有用。

自定义提供给解析器的源值

默认情况下,
AutoMapper
将源对象传递给解析器。 这限制了解析器的可重用性,因为解析器被耦合到源类型。 但是,如果我们提供跨多种类型的通用解析器,我们将
AutoMapper
配置为重定向提供给解析器的源值,并使用不同的解析器接口,以便我们的解析器可以使用源/目标成员:

Mapper.Initialize(cfg => {
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total,
opt => opt.ResolveUsing<CustomResolver, decimal>(src => src.SubTotal));
cfg.CreateMap<OtherSource, OtherDest>()
.ForMember(dest => dest.OtherTotal,
opt => opt.ResolveUsing<CustomResolver, decimal>(src => src.OtherSubTotal));
});

public class CustomResolver : IMemberValueResolver<object, object, decimal, decimal> {
public decimal Resolve(object source, object destination, decimal sourceMember, decimal destinationMember, ResolutionContext context) {
//逻辑在这里
}
}


将键值对传递给
Mapper

在调用映射时,可以使用键值传递额外的对象,并使用自定义解析器从上下文获取对象。

Mapper.Map<Source, Dest>(src, opt => opt.Items["Foo"] = "Bar");


这是如何设置这个自定义解析器的映射

Mapper.CreateMap<Source, Dest>()
.ForMember(d => d.Foo, opt => opt.ResolveUsing((src, dest, destMember, res) => res.Context.Options.Items["Foo"]));


ForPath

ForMember
相似,从6.1.0开始有
ForPath
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: