AutoMapper 自定义类型转换
有时,您需要完全控制一种类型到另一种类型的转换。这通常发生在两种类型看起来完全不同、已经存在转换函数,并且您希望从较 “宽松” 的类型转换为更严格的类型时,例如从源类型 string
转换为目标类型 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>;
第一种选项是任何接受源并返回目标的函数(也有多个重载)。这对于简单情况有效,但对于较大问题则变得笨拙。在更复杂的情况下,我们可以创建一个自定义的 ITypeConverter
接口:
public interface ITypeConverter<in TSource, TDestination>
{
TDestination Convert(TSource source, TDestination destination, ResolutionContext context);
}
并向 AutoMapper
提供自定义类型转换器的实例,或者只是类型本身,AutoMapper
将在运行时实例化。对于上面的源/目标类型,映射配置变为:
[Test]
public void Example()
{
var configuration = new MapperConfiguration(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>();
});
configuration.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
发现任何映射类型上的 source/destination
,就会使用它们。我们可以构建一套自定义类型转换器,其他映射配置可以在此基础上使用,无需额外配置。在上述示例中,我们再也不需要再次指定 string
到 int
的转换。而 自定义值解析器 必须在类型成员级别进行配置,自定义类型转换器则是全局范围的。