簡體   English   中英

我如何使用 Automapper 在兩個枚舉之間進行 map?

[英]How can I map between two enums using Automapper?

我有一個面向公眾的界面,我正在嘗試 map 兩個不同的枚舉。 我嘗試使用以下代碼:

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>();

當那不起作用時,我嘗試了:

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>().ConvertUsing(x => (Common.ValidationResultType)((int)x));

但這似乎也不起作用。 無論如何讓自動映射器來處理這種情況?

或者編寫自定義轉換器,只需使用 ConvertUsing()

Mapper.CreateMap<EnumSrc, EnumDst>().ConvertUsing(value => 
{
    switch(value)
    {
        case EnumSrc.Option1:
            return EnumDst.Choice1;
        case EnumSrc.Option2:
            return EnumDst.Choice2;
        case EnumSrc.Option3:
            return EnumDst.Choice3;
        default:
            return EnumDst.None;
    }
});

您不需要為枚舉類型執行 CreateMap。 只要擺脫 CreateMap 調用,它應該可以工作,只要枚舉類型之間的名稱和/或值匹配。

我的 Automapper 是這樣工作的:

如果我創建地圖: Automapper 將按值匹配枚舉,即使名稱完全匹配。

如果我不創建地圖: Automapper 將按名稱匹配枚舉。

我發現對我有用的最簡單方法如下:

我的 Enum 嵌套在另一個類中,所以我使用 ForMember 方法和 MapFrom 如下:

 Mapper.CreateMap<ProblematicCustomer, ProblematicCustomerViewModel>()                
            .ForMember(m=> m.ProblemType, opt=> opt.MapFrom(x=> (ProblemTypeViewModel)(int)x.ProblemType))
            .ForMember(m=> m.JudgmentType, opt=> opt.MapFrom(x=> (JudgmentTypeViewModel)(int)x.JudgmentType));

ProblemType 和 JudgmentType 是枚舉。 並且它們相關的視圖模型是 ProblemTypeViewModel 和 JudgmentTypeViewModel 與它們的相關模型具有相同的成員。

雖然我不測試,但我認為下面這行應該適合你:

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>()
           .ForMember(m=> m, opt => opt.MapFrom(x=> (Common.ValidationResultType)(int)x);

希望它有幫助。

這里的其他答案對我不起作用。

您需要創建一個實現的類:

ITypeConvertor<SourceType ,DestinationType>

所以作為一個例子

 Mapper.CreateMap<EnumType1.VatLevel, EnumType2.VatRateLevel>()
       .ConvertUsing(new VatLevelConvertor());

和班級:

internal class VatLevelConvertor : ITypeConverter<EnumType1.VatLevel, EnumType2.VatRateLevel>
{
    public EnumType2.VatRateLevel Convert(ResolutionContext context)
    {
        EnumType1.VatLevel value = (EnumType1.VatLevel)context.SourceValue;
        switch (value)
        {
            case EnumType1.VatLevel.Standard:
                return EnumType2.VatRateLevel.Normal;
            case EnumType1.VatLevel.Reduced:
                return EnumType2.VatRateLevel.Lower;
            case EnumType1.VatLevel.SuperReduced:
                return EnumType2.VatRateLevel.Other;
            default:
                return EnumType2.VatRateLevel.Other;
        }
    }
}

這是在兩個具有不同值的 Enum 類型之間進行轉換的一種可能性,同時仍然使用 AutoMapper。 就我而言,我需要使用 AutoMapper,因為 Enum 類型是 AutoMapper 轉換的其他實體的屬性; 對這些實體使用 AutoMapper 是一項要求。

第一步是像這樣設置 Mapper 配置:

Mapper.CreateMap<EnumSrc, EnumDst>()
    .ConstructUsing(EnumConversion.FromSrcToDst);

調用.ConstructUsing(...)允許我們傳入我們自己的方法來進行轉換。 轉換方法非常簡單:

public class EnumConversion
{
    internal static EnumDst FromSrcToDst(ResolutionContext arg)
    {
        EnumSrc value = (EnumSrc)arg.SourceValue;
        switch(value)
        {
            case EnumSrc.Option1:
                return EnumDst.Choice1;
            case EnumSrc.Option2:
                return EnumDst.Choice2;
            case EnumSrc.Option3:
                return EnumDst.Choice3;
            default:
                return EnumDst.None;
        }
    }
}

我們簡單地switch源 Enum 的值並任意返回適當的目標 Enum 值。 AutoMapper 負責其余的工作。

只需為兩個枚舉創建一個映射器,就是這樣! Automapper 將通過 Enum 的匹配值或索引值進行映射。 (例如草稿 -> 步驟 1)

public enum SourceStatus
{
    Draft,
    Submitted,
    Deleted
}

public enum DestinationStatus
{
    Step1,
    Step2,
    Step3
}

public class SourceObj
{
    public SourceStatus Status { get; set; }
}

public class DestinationObj
{
    public DestinationStatus Status { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        //Static APi style - this is obsolete now. From Version 5.0 onwards    this will be removed.
        SourceObj mySrcObj = new SourceObj();
        mySrcObj.Status = SourceStatus.Deleted;

        Mapper.CreateMap<SourceStatus, DestinationStatus>();
        Mapper.CreateMap<SourceObj, DestinationObj>();

        DestinationObj myDestObj = Mapper.Map<SourceObj, DestinationObj>(mySrcObj);

        //New way of doing it
        SourceObj mySrcObj2 = new SourceObj();
        mySrcObj2.Status = SourceStatus.Draft;

        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<SourceObj, DestinationObj>();
        });

        IMapper mapper = config.CreateMapper();
        var source = new SourceObj();
        var dest = mapper.Map<SourceObj, DestinationObj>(source);



    }
}

我試圖使用 Automapper 在“相等”枚舉之間進行映射,但不幸的是它不起作用。 我懷疑問題是大小寫不同:

public enum Foo {
    val1,
    val2
}

public enum Bar {
    Val1,
    Val2
}

Foo是從 XSD 自動生成的東西,供應商很糟糕。 還有三十多歲的值,我不想在任何地方放一個這么大的switch來做這么愚蠢的事情。

我采用的方法是將源值轉換為字符串並將其解析為目標值:

static Foo ConvertEnum(Bar source)
{
    Foo result;
    var parsed = Enum.TryParse(source.ToString().ToLowerInvariant(), true, out result);
    if(!parsed)
         // throw or return default value
         throw new ArgumentOutOfRangeException("source", source, "Unknown source value");
    return result;
}

當然,這僅在您的枚舉僅在大小寫上有差異時才有效。 您可以通過清理輸入字符串(例如刪除下划線等)或根據需要向其中添加內容來使其更加復雜。

我知道這個問題很老,但如果像我這樣的人路過這里......

AutoMapper 文檔中,現在有一個AutoMapper.Extensions.EnumMapping Nuget 包提供了一種簡單的方法來做到這一點。

引用 AutoMapper 文檔:


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
                // optional: .MapByValue() or MapByName(), without configuration MapByValue is used
                .MapValue(Source.First, Destination.Default)
            )
            .ReverseMap(); // to support Destination to Source mapping, including custom mappings of ConvertUsingEnumMapping
    }
}

我知道這是一個非常古老的話題,但它是我在谷歌搜索時得到的主要話題,所以決定展示我的發現。

我有源和目標枚舉。 它們不完全匹配,但有時值(數字值)可能會重疊,但該匹配可能不正確。 為了說明,這里有 2 個枚舉:

enum EnumA {
  Item1 = 5,
  Item2 = 10,
  Item3 = 15
}

enum EnumB {
  I1 = 15,
  I2 = 10,
  I3 = 5
}

我想在兩者之間有一個明確的 map,所以我有一個這樣的開關盒:

source switch {
  EnumA.Item1 => EnumB.I1,
  EnumA.Item2 => EnumB.I2,
  EnumA.Item3 => EnumB.I3,
  _ => throw new ArgumentException("")
}

到目前為止,一切順利,這按預期工作。 當我試圖將它掛接到 AutoMapper 時,有趣的部分出現了。

我定義了這樣的映射

CreateMap<EnumA, EnumB>().ConvertUsing((src, dest) => src switch {
  EnumA.Item1 => EnumB.I1,
  EnumA.Item2 => EnumB.I2,
  EnumA.Item3 => EnumB.I3,
  _ => throw new ArgumentException("")
});

然后作為普通會員使用 map

.ForMember(dest => dest.PropA, opts => opts.MapFrom(src => src.PropB))

但是,使用此代碼,當數字 ID 匹配時,我會得到錯誤的枚舉成員。

我能讓它工作的唯一方法是定義一個值轉換器

public class ItemConverter : IValueConverter<EnumA, EnumB>
{
  public CountryCode Convert(EnumA sourceMember, ResolutionContext context) => sourceMember switch
  {
    EnumA.Item1 => EnumB.I1,
    EnumA.Item2 => EnumB.I2,
    EnumA.Item3 => EnumB.I3,
    _ => throw new ArgumentException("")
  }
}

並像這樣使用它:

.ForMember(dest => dest.PropA, opts => opts.ConvertUsing(new ItemConverter(), src => src.PropB))

希望它能幫助將來像我這樣的人

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM