项目
版本

AutoMapper 枚举映射

内置的枚举映射器不可配置,只能被替换。作为替代方案,AutoMapper 在一个独立的包 AutoMapper.Extensions.EnumMapping 中支持基于约定的枚举值映射功能。

使用方法

对于 CreateMap 方法,这个库提供了一个 ConvertUsingEnumMapping 方法。此方法会添加从源枚举到目标枚举值的所有默认映射。

如果你想更改某些映射,则可以使用 MapValue 方法。这是一个可链式调用的方法。

默认情况下,枚举值按值(明确地说是:MapByValue())映射,但也可以通过调用 MapByName() 来按名称映射。

using AutoMapper.Extensions.EnumMapping;

public enum Source
{
    Default = 0,
    First = 1,
    Second = 2
}

public enum Destination
{
    Default = 0,
    Second = 2
}

internal class YourProfile : Profile
{
    public YourProfile()
    {
        CreateMap<Source, Destination>()
            .ConvertUsingEnumMapping(opt => opt
		        // 可选:.MapByValue() 或 MapByName(),如果不进行配置,默认使用 MapByValue
		        .MapValue(Source.First, Destination.Default)
            )
            .ReverseMap(); // 支持从 Destination 到 Source 的映射,包括 ConvertUsingEnumMapping 的自定义映射
    }
}
    ...

默认约定

AutoMapper.Extensions.EnumMapping 会将源类型的所有值映射到目标类型,如果这两个枚举类型具有相同的值(或按名称或按值)。所有没有目标等价物的源枚举值,在启用 EnumMappingValidation 时,将会抛出异常。

ReverseMap 约定

对于 ReverseMap 方法,使用的约定与默认映射相同,但它也会尊重可能的枚举值映射覆盖。

确定反向覆盖的步骤如下:

  1. SourceDestination 创建映射(使用默认约定),包括自定义覆盖。

  2. DestinationSource 创建映射(使用默认约定),不包括自定义覆盖(需要确定)。

  3. 步骤 1 中创建的映射将用于确定 ReverseMap 的覆盖。因此,映射将按 Destination 值分组。

    3a) 如果有匹配的 `Source` 值对应于 `Destination` 值,则优先选择该映射,不需要覆盖。
    

    可能存在一个 Destination 值对应多个通过覆盖映射指定的 Source 值。

    我们必须确定哪个 Source 值将成为当前 Destination 值(现在是新的 Source 值)的新 Destination

    对于每个按 Destination 值分组的 Source 值:

    3b) 如果 `Source` 枚举值在 `Destination` 枚举类型中不存在,则该映射无法反转。
    3c) 如果有不是步骤1中映射部分的 `Source` 值,则该映射无法反转。
    3d) 如果 `Source` 值未被选项b和c排除,则该 `Source` 值就是新的 `Destination` 值。
    
  4. 步骤 3 中确定的所有覆盖将应用于步骤 2 中的映射。

  5. 最后,提供给 ReverseMap 方法的自定义映射将被应用。

测试

AutoMapper 提供了验证类型映射的便捷工具。这个包添加了一个额外的 EnumMapperConfigurationExpressionExtensions.EnableEnumMappingValidation 扩展方法,以扩展现有的 AssertConfigurationIsValid() 方法来同时验证枚举映射配置。

为了启用枚举映射配置的测试:

public class MappingConfigurationsTests
{
    [Fact]
    public void WhenProfilesAreConfigured_ItShouldNotThrowException()
    {
        // Arrange
        var config = new MapperConfiguration(configuration =>
        {
            configuration.EnableEnumMappingValidation();

            configuration.AddMaps(typeof(AssemblyInfo).GetTypeInfo().Assembly);
        });

        // Assert
        config.AssertConfigurationIsValid();
    }
}
在本文档中