https://www.jianshu.com/p/47054d92db2a
自定义类型转换器(Custom Type Converters)
有时需要完全控制一种类型到另一种类型的转换。这一般发生在两种类型不同,已经存在转换函数,并且希望从弱类型转变为强类型,如源类型的字符串到目标类型Int32。
例如,假设我们的源类型为:
public class Source
{
public string Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
你又想映射到以下目标类型:
public class Destination
{
public int Value1 { get; set; }
public DateTime Value2 { get; set; }
public Type Value3 { get; set; }
}
如果我们尝试直接映射这两种类型, AutoMapper
将抛出一个异常 (在执行映射时和配置检查时), 因为AutoMapper
不知道从string
到int
,DateTime
或Type
的该如何映射。 要为这些类型创建映射,我们必须提供自定义类型转换器,我们有以下三种方法:
void ConvertUsing(Func<TSource, TDestination> mappingFunction);
void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;
第一种方法是写一个委托来指定如何转换源类型到目标类型。如
cfg.CreateMap<string,int>().ConvertUsing(s=>Convert.ToInt32(s));
这种方法只能处理简单类型的情况,针对复合类型的情况我们需要创建自定义的ITypeConverter<TSource, TDestination>
转换器:
public interface ITypeConverter<in TSource, TDestination>
{
TDestination Convert(TSource source, TDestination destination, ResolutionContext context);
}
为AutoMapper
提供自定义类型转换器的实例,或者只提供类型,AutoMapper
将在运行时实例化。然后,上面的源/目标类型的映射配置变为:
[Test]
public void Example()
{
Mapper.Initialize(cfg => {
cfg.CreateMap<string, int>().ConvertUsing(s => Convert.ToInt32(s));
cfg.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());
cfg.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();
cfg.CreateMap<Source, Destination>();
});
Mapper.AssertConfigurationIsValid();
var source = new Source
{
Value1 = "5",
Value2 = "01/01/2000",
Value3 = "AutoMapperSamples.GlobalTypeConverters.GlobalTypeConverters+Destination"
};
Destination result = Mapper.Map<Source, Destination>(source);
result.Value3.ShouldEqual(typeof(Destination));
}
public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
{
public DateTime Convert(string source, DateTime destination, ResolutionContext context)
{
return System.Convert.ToDateTime(source);
}
}
public class TypeTypeConverter : ITypeConverter<string, Type>
{
public Type Convert(string source, Type destination, ResolutionContext context)
{
return Assembly.GetExecutingAssembly().GetType(source);
}
}
在第一个映射中,从string到Int32,我们只使用内置的Convert.ToInt32函数。
接下来的两个映射使用了自定义ITypeConverter实现。
自定义类型转换器的真正强大的地方在于,AutoMapper
可以在任何源/目标类型上使用它们。我们可以在使用其他映射配置上方构建一组自定义类型转换器,而无需任何额外配置。在上面的例子中,我们永远不需要再次指定string/int 转换。如果必须在类型成员级别配置自定义值解析器,则自定义类型转换器的范围是全局的。
系统类型转换器
.NETFramework
通过TypeConverter
类支持类型转换器的概念。AutoMapper
在配置检查和映射时支持这些类型的类型转换器,而且不需要手动配置。AutoMappe
通过使用TypeDescriptor.GetConverter
方法确定源/目标类型是否可映射。