web-dev-qa-db-ja.com

Automapperを使用して2つの列挙間をマップするにはどうすればよいですか?

2つの異なる列挙を相互にマッピングしようとしている公開インターフェイスがあります。私は次のコードを使用しようとしました:

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

それがうまくいかなかったとき、私は試しました:

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

しかし、それでもうまくいかないようです。とにかくオートマッパーにこのシナリオを処理させる方法はありますか?

46
Jeffrey Lott

列挙型に対してCreateMapを実行する必要はありません。名前や値が列挙型間で一致する限り、CreateMap呼び出しを取り除くだけで機能します。

41
Jimmy Bogard

カスタムコンバーターを記述する代わりに、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;
    }
});
57

私のAutomapperは次のように機能します。

マップを作成する場合: Automapperは、名前が完全に一致する場合でも、値によって列挙型を一致させます。

マップを作成しない場合: Automapperは、名前で列挙型を照合します。

10
Piotr Kwiatek

私にとって最も簡単な方法は次のとおりです。

私の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とJudgementTypeはEnumです。また、関連するビューモデルはProblemTypeViewModelとJudgmentTypeViewModelであり、関連するモデルと同じメンバーです。

私はテストしませんが、以下の行があなたのために働くはずだと思います:

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

それが役立つことを願っています。

4
mesut

2つのEnumのマッパーを作成するだけです! 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);



    }
}
3
Dhanuka777

ここでの他の答えは私にはうまくいきませんでした。

以下を実装するクラスを作成する必要があります。

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;
        }
    }
}
3
Neil

AutoMapperを使用したまま、値が異なる2つのEnum型の間で変換を行う可能性が1つあります。私の場合、Enum型はAutoMapperによって変換される他のエンティティのプロパティであるため、AutoMapperを使用する必要がありました。これらのエンティティにAutoMapperを使用することが要件でした。

最初のステップは、マッパー構成を次のようにセットアップすることです。

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

ソースEnumの値を単にswitchして、適切な宛先Enum値を任意に返します。 AutoMapperが残りを処理します。

3
Trevor

Automapperを使用して「等しい」列挙型間をマッピングしようとしましたが、残念ながら機能しませんでした。私は問題がケーシングの違いだと思う:

public enum Foo {
    val1,
    val2
}

public enum Bar {
    Val1,
    Val2
}

FooはXSDから自動生成されたものであり、サプライヤは気の毒です。また、30の値があり、非常にばかげたもののために、その大きさの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;
}

もちろん、これは列挙型の大文字と小文字が異なる場合にのみ機能します。入力文字列をクリーンアップする(たとえば、アンダースコアを削除するなど)か、必要に応じて何かを追加することで、より複雑にすることができます。

2
MarioDS