एक एनुम को दूसरे प्रकार के एनम में परिवर्तित करें


120

मेरे पास उदाहरण के लिए एक एनम है ' Gender' ( Male =0 , Female =1) और मेरे पास एक और एनम है एक सेवा से जिसका अपना जेंडर एनम है Male =0 , Female =1, Unknown =2)

मेरा सवाल यह है कि मैं अपनी ईमू से खदान में परिवर्तित करने के लिए कुछ त्वरित और अच्छा कैसे लिख सकता हूं?


6
आप "अज्ञात" को किस में बदलना चाहते हैं?
पावेल मिनाएव

जब आप दोनों समान मान रखते हैं, तो आप एनम
Gowtham S

जवाबों:


87

नैट द्वारा सुझाए गए दो रूपांतरण तरीकों का उपयोग करते समय, एक विस्तार विधि का उपयोग करना काफी करीने से काम करता है:

public static class TheirGenderExtensions
{
    public static MyGender ToMyGender(this TheirGender value)
    {
        // insert switch statement here
    }
}

public static class MyGenderExtensions
{
    public static TheirGender ToTheirGender(this MyGender value)
    {
        // insert switch statement here
    }
}

यदि आप नहीं चाहते हैं, तो स्पष्ट रूप से अलग-अलग कक्षाओं का उपयोग करने की कोई आवश्यकता नहीं है। मेरी प्राथमिकता उन वर्गों / संरचनाओं / गणनाओं द्वारा वर्गीकृत विस्तार विधियों को रखना है, जिन पर वे लागू होते हैं।


233

दिया गया है Enum1 value = ..., तो अगर आप नाम से मतलब है:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());

यदि आप संख्यात्मक मूल्य से मतलब रखते हैं, तो आप आमतौर पर सिर्फ कास्ट कर सकते हैं:

Enum2 value2 = (Enum2)value;

(कलाकारों के साथ, आप Enum.IsDefinedमान्य मानों की जांच के लिए उपयोग करना चाह सकते हैं , हालांकि)


16
यह बेहतर उत्तर है
निकोलस

1
यहां एक संस्करण है जो उपयोग करता है Enum.Tryparse: Enum2 value2 = Enum.TryParse(value.ToString(), out Enum2 outValue) ? outValue : Enum2.Unknown; यह आपको इनपुट मानों को संभालने की अनुमति देगा जो कि एस द्वारा फेंके गए Enum2कॉल Enum.IsDefinedया पकड़ने की आवश्यकता के बिना मौजूद नहीं हैं । ध्यान दें कि मापदंडों का क्रम कमोबेश उलटा है । ArgumentExceptionEnum.ParseEnum.Parse
सैंडर

47

बस एक इंट करने के लिए डाल दिया और फिर इसे अन्य एनम (यह मानकर कि आप मूल्य के आधार पर की गई मैपिंग चाहते हैं) को कास्ट करें:

Gender2 gender2 = (Gender2)((int)gender1);

3
यद्यपि इसे 'जंगली' में देखने की संभावना नहीं है, और लिंग के मामले में इसकी संभावना बहुत अधिक है, फिर भी कुछ ईनम मौजूद हो सकते हैं जो एक long(या ulong) द्वारा समर्थित है, बजाय intइसके कि सदस्यों को परिभाषित किया गया है जो ऊपर int.MaxValue(या नीचे) हैं int.MinValue), जिस स्थिति में कलाकार intओवरफ्लो कर सकते हैं और आप एक अपरिभाषित ईनम मान के साथ समाप्त हो जाएंगे जिसे परिभाषित किया जाना चाहिए।
रिच ओ'केली जूल

बेशक। सही तरीका होगा (Gender2) ((यहाँ अंतर्निहित प्रकार डालें) लिंग 1) लेकिन मुझे लगता है कि ऊपर दिया गया उदाहरण सही विचार देता है इसलिए मैं इसे नहीं बदलूंगा।
एड्रियन ज़ैनस्कु

3
इसके लिए आवश्यक है कि दोनों एनम समान क्रम में समान मान रखें। हालांकि यह इस विशिष्ट समस्या को हल करता है, यह वास्तव में भंगुर है और मैं सामान्य रूप से एनम मैपिंग के लिए इसका उपयोग नहीं करूंगा।
sonicblis

2
खैर दुह! । कुछ के आधार पर मैपिंग की जरूरत है। इस मामले में मानचित्रण अभिन्न मूल्य पर है। नाम के आधार पर मैपिंग के लिए आपको अलग कोड की आवश्यकता होती है। किसी और तरह की मैपिंग के लिए। नोयन ने कहा कि यह "सामान्य रूप से एनम मैपिंग के लिए" है और यह मामला तब तक मौजूद नहीं है जब तक कि आप यह निर्दिष्ट करने की कोशिश न करें कि "सामान्य रूप से मैपिंग" का अर्थ क्या है
एड्रियन ज़ैनस्कु

20

पूरी तरह से होने के लिए, मैं आम तौर पर कार्यों की एक जोड़ी बनाता हूं, एक जो Enum 1 लेता है और Enum 2 देता है और दूसरा Enum 2 लेता है और Enum 1 लौटाता है। प्रत्येक में एक केस स्टेटमेंट होता है जिसमें आउटपुट के लिए इनपुट मैपिंग होती है और डिफ़ॉल्ट केस अपवाद को छोड़ देता है। एक अप्रत्याशित मूल्य के बारे में शिकायत करने वाला संदेश।

इस विशेष मामले में आप इस तथ्य का लाभ उठा सकते हैं कि पुरुष और महिला के पूर्णांक मान समान हैं, लेकिन मैं इससे बचना चाहूंगा, क्योंकि यह हैकिश है और टूटना के अधीन है यदि भविष्य में कोई भी परिवर्तन करता है।


7
+1 मैंने कई डेवलपर्स को उन्हें परिवर्तित करने के लिए एनम के पूर्णांक मान का उपयोग करने के आग्रह को देखा है, लेकिन यह बहुत त्रुटि वाला है। 2 कार्यों को लिखने की पुरानी स्कूल विधि ने समय के साथ अपनी योग्यता साबित की ...
हेमंत

20

अगर हमारे पास है:

enum Gender
{
    M = 0,
    F = 1,
    U = 2
}

तथा

enum Gender2
{
    Male = 0,
    Female = 1,
    Unknown = 2
}

हम सुरक्षित रूप से कर सकते हैं

var gender = Gender.M;
var gender2   = (Gender2)(int)gender;

या और भी

var enumOfGender2Type = (Gender2)0;

यदि आप उस मामले को कवर करना चाहते हैं, जहां बाईं ओर के एनम की तुलना में '=' ​​चिह्न के दाईं ओर एक एनम अधिक मान है - तो आपको अपने स्वयं के तरीके / शब्दकोश को लिखना होगा, जिसमें अन्य सुझाव दिए गए हैं।


आपका जवाब एक सवाल पूछने की तरह है !? यदि हाँ, तो यह एक उत्तर नहीं है और यदि नहीं तो ऊपर एक समान उत्तर है ;)।
shA.t

13

आप इस तरह एक सरल सामान्य विस्तार विधि लिख सकते हैं

public static T ConvertTo<T>(this object value)            
    where T : struct,IConvertible
{
    var sourceType = value.GetType();
    if (!sourceType.IsEnum)
        throw new ArgumentException("Source type is not enum");
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Destination type is not enum");
    return (T)Enum.Parse(typeof(T), value.ToString());
}

1
यह उपरोक्त उत्तरों में सुझाए गए मानों के लापता होने के मामले को कवर नहीं करता है। आपको इस मामले को कवर करते हुए इस विस्तार विधि को भी संशोधित करना चाहिए।
eRaisedToX

8

आप निम्नलिखित की तरह एक साधारण कार्य लिख सकते हैं:

public static MyGender ConvertTo(TheirGender theirGender)
{
    switch(theirGender)
    {
        case TheirGender.Male:
            break;//return male
        case TheirGender.Female:
            break;//return female
        case TheirGender.Unknown:
            break;//return whatever
    }
}

1
यह एक फ़ंक्शन नहीं है। अपेक्षित 'MyGender' और आप 'void' लौटा रहे हैं
bl4ckr0se

7

अगर किसी की दिलचस्पी है तो यहां एक विस्तार विधि संस्करण है

public static TEnum ConvertEnum<TEnum >(this Enum source)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true);
    }

// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();

क्या इसका मतलब यह नहीं है कि दोनों गणनाओं में समान संख्यात्मक मूल्य हैं?
कुस्कमेन

1
नहीं, यह स्ट्रिंग द्वारा नाम से परिवर्तित हो रहा है। तो Enum.Foo (1) Enum2.Foo (2) में अनुवाद करेगा, भले ही उनके संख्यात्मक मान अलग-अलग हों।
जस्टिन

3
public static TEnum ConvertByName<TEnum>(this Enum source, bool ignoreCase = false) where TEnum : struct
{
    // if limited by lack of generic enum constraint
    if (!typeof(TEnum).IsEnum)
    {
        throw new InvalidOperationException("enumeration type required.");
    }

    TEnum result;
    if (!Enum.TryParse(source.ToString(), ignoreCase, out result))
    {
        throw new Exception("conversion failure.");
    }

    return result;
}

2

मैंने कुछ समय पहले एक सेट एक्सटेंशन मेथड लिखा था जो कई तरह के Enumएस के लिए काम करता है । आप क्या हासिल करने की कोशिश कर रहे हैं और हैंडल के लिए विशेष रूप से काम करता है में से एक Enumके साथ FlagsAttributeके साथ ही Enumविभिन्न प्रकार के साथ अंतर्निहित है।

public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable
{
    if (typeCheck)
    {
        if (e.GetType() != flags.GetType())
            throw new ArgumentException("Argument is not the same type as this instance.", "flags");
    }

    var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum));

    var firstNum = Convert.ToUInt32(e);
    var secondNum = Convert.ToUInt32(flags);

    if (set)
        firstNum |= secondNum;

    else
        firstNum &= ~secondNum;

    var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType);

    if (!typeCheck)
    {
        var values = Enum.GetValues(typeof(tEnum));
        var lastValue = (tEnum)values.GetValue(values.Length - 1);

        if (newValue.CompareTo(lastValue) > 0)
            return lastValue;
    }

    return newValue;
}

वहां से आप अन्य विशिष्ट एक्सटेंशन विधियों को जोड़ सकते हैं।

public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, true);
}

public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, false);
}

यह एक के प्रकार बदल जाएगा Enumजैसे आप करने की कोशिश कर रहे हैं।

public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
    return SetFlags(e, default(tEnum), true, false);
}

हालांकि, चेतावनी दी जाती है कि आप इस पद्धति का उपयोग करके Enumकिसी भी और किसी भी व्यक्ति के बीच परिवर्तित कर सकते हैं Enum, यहां तक ​​कि जिनके पास झंडे नहीं हैं। उदाहरण के लिए:

public enum Turtle
{
    None = 0,
    Pink,
    Green,
    Blue,
    Black,
    Yellow
}

[Flags]
public enum WriteAccess : short
{
   None = 0,
   Read = 1,
   Write = 2,
   ReadWrite = 3
}

static void Main(string[] args)
{
    WriteAccess access = WriteAccess.ReadWrite;
    Turtle turtle = access.ChangeType<Turtle>();
}

चर turtleका मान होगा Turtle.Blue

हालांकि, Enumइस पद्धति का उपयोग करके अपरिभाषित मूल्यों से सुरक्षा है । उदाहरण के लिए:

static void Main(string[] args)
{
    Turtle turtle = Turtle.Yellow;
    WriteAccess access = turtle.ChangeType<WriteAccess>();
}

इस मामले में , के बाद से accessसेट किया जाएगाWriteAccess.ReadWriteWriteAccess Enum 3 के अधिकतम मूल्य के ।

मिक्सिंग और इसके बिना उन लोगों के Enumसाथ मिश्रण का एक और दुष्प्रभाव FlagsAttributeयह है कि रूपांतरण की प्रक्रिया उनके मूल्यों के बीच 1 से 1 मैच नहीं होगी।

public enum Letters
{
    None = 0,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H
}

[Flags]
public enum Flavors
{
    None = 0,
    Cherry = 1,
    Grape = 2,
    Orange = 4,
    Peach = 8
}

static void Main(string[] args)
{
    Flavors flavors = Flavors.Peach;
    Letters letters = flavors.ChangeType<Letters>();
}

इस मामले में, lettersके एक मूल्य होगा Letters.Hबजाय Letters.D, के बाद से के समर्थन मूल्य Flavors.Peach8. इसके अलावा है से एक रूपांतरण, Flavors.Cherry | Flavors.Grapeको Lettersप्राप्त होते हैं Letters.C, जो unintuitive लग सकता है।


2

जस्टिन के उत्तर के आधार पर मैं इसके साथ आया:

    /// <summary>
    /// Converts Enum Value to different Enum Value (by Value Name) See https://stackoverflow.com/a/31993512/6500501.
    /// </summary>
    /// <typeparam name="TEnum">The type of the enum to convert to.</typeparam>
    /// <param name="source">The source enum to convert from.</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public static TEnum ConvertTo<TEnum>(this Enum source)
    {
        try
        {
            return (TEnum) Enum.Parse(typeof(TEnum), source.ToString(), ignoreCase: true);
        }
        catch (ArgumentException aex)
        {
            throw new InvalidOperationException
            (
                $"Could not convert {source.GetType().ToString()} [{source.ToString()}] to {typeof(TEnum).ToString()}", aex
            );
        }
    }

1

मुझे पता है कि यह एक पुराना प्रश्न है और इसके बहुत सारे उत्तर हैं, हालांकि मुझे लगता है कि स्वीकार किए गए उत्तर में स्विच स्टेटमेंट का उपयोग करना कुछ बोझिल है, इसलिए यहां मेरे 2 सेंट हैं:

मेरी व्यक्तिगत पसंदीदा विधि एक शब्दकोश का उपयोग करना है, जहां कुंजी स्रोत ईनम है और मूल्य लक्ष्य एनम है - इसलिए प्रश्न पर प्रस्तुत मामले में मेरा कोड इस तरह दिखेगा:

var genderTranslator = new Dictionary<TheirGender, MyGender>();
genderTranslator.Add(TheirGender.Male, MyGender.Male);
genderTranslator.Add(TheirGender.Female, MyGender.Female);
genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown);

// translate their to mine    
var myValue = genderTranslator[TheirValue];

// translate mine to their
var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;;

बेशक, इसे एक स्थिर वर्ग में लपेटा जा सकता है और इसे विस्तार विधियों के रूप में उपयोग किया जा सकता है:

public static class EnumTranslator
{

    private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator();

    private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator()
    {
        var translator = new Dictionary<TheirGender, MyGender>();
        translator.Add(TheirGender.Male, MyGender.Male);
        translator.Add(TheirGender.Female, MyGender.Female);
        translator.Add(TheirGender.Unknown, MyGender.Unknown);
        return translator;
    }

    public static MyGender Translate(this TheirGender theirValue)
    {
        return GenderTranslator[theirValue];
    }

    public static TheirGender Translate(this MyGender myValue)
    {
        return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key;
    }

}

मुझे यह तरीका पसंद है क्योंकि आप शब्दकोष को पॉप्युलेट करने के लिए दोनों गणनाओं की गणना कर सकते हैं। (जब वे समान क्रम में हों)
एलेक्स्स

0

आप पहले Enum को उसके नाम में बदलने के लिए ToString () का उपयोग कर सकते हैं, और फिर Enum.Parse () से स्ट्रिंग को दूसरे Enum में बदलने के लिए। यदि मान गंतव्य Enum ("अज्ञात" मान के लिए) द्वारा समर्थित नहीं है, तो यह एक अपवाद को फेंक देगा

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.