项目
版本

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 映射到 intDateTimeType。为了创建这些类型的映射,我们必须提供一个自定义类型转换器,我们有三种方法来实现:

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);
    }
}

在第一个映射中,从 stringInt32,我们直接使用内置的 Convert.ToInt32 函数(以方法组的形式提供)。接下来两个使用自定义的 ITypeConverter 实现。

自定义类型转换器的真正强大之处在于,只要 AutoMapper 发现任何映射类型上的 source/destination ,就会使用它们。我们可以构建一套自定义类型转换器,其他映射配置可以在此基础上使用,无需额外配置。在上述示例中,我们再也不需要再次指定 stringint 的转换。而 自定义值解析器 必须在类型成员级别进行配置,自定义类型转换器则是全局范围的。

在本文档中