c# - एक एनम की स्ट्रिंग का प्रतिनिधित्व




enums (20)

.NET 4.0 और ऊपर के साथ इसका बहुत आसान समाधान। कोई अन्य कोड की आवश्यकता नहीं है।

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

केवल उपयोग के बारे में स्ट्रिंग प्राप्त करने के लिए:

MyStatus.Active.ToString("f");

या

MyStatus.Archived.ToString("f");`

मान "सक्रिय" या "संग्रहीत" होगा।

Enum.ToString कॉल करते समय विभिन्न स्ट्रिंग प्रारूप (ऊपर से "एफ") देखने के लिए इस गणना प्रारूप स्ट्रिंग्स पृष्ठ को देखें

मेरे पास निम्नलिखित गणना है:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

समस्या यह है कि जब मैं प्रमाणीकरण Method.FORMS के लिए पूछता हूं और आईडी 1 नहीं तो मुझे "FORMS" शब्द की आवश्यकता होती है।

मुझे इस समस्या के लिए निम्नलिखित समाधान मिला है ( link ):

सबसे पहले मुझे "स्ट्रिंगवैल्यू" नामक एक कस्टम विशेषता बनाने की आवश्यकता है:

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

फिर मैं इस गुण को अपने गणक में जोड़ सकता हूं:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

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

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

अच्छा अब मुझे एक गणक के लिए स्ट्रिंग मान प्राप्त करने के लिए टूल मिल गए हैं। मैं इसके बाद इसका उपयोग कर सकता हूं:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

ठीक है अब ये सभी काम एक आकर्षण की तरह हैं लेकिन मुझे यह बहुत काम मिल रहा है। मैं सोच रहा था कि इसके लिए एक बेहतर समाधान है या नहीं।

मैंने एक शब्दकोश और स्थिर गुणों के साथ कुछ भी करने की कोशिश की लेकिन यह बेहतर नहीं था।


आप ToString () का उपयोग करके मूल्य के बजाय नाम का संदर्भ दे सकते हैं

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

दस्तावेज यहां है:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

... और यदि आप पास्कल केस में अपने enums का नाम देते हैं (जैसा कि मैं करता हूं - जैसे कि यह IsMyEnumValue = 1 आदि) तो आप दोस्ताना रूप प्रिंट करने के लिए एक बहुत ही सरल रेगेक्स का उपयोग कर सकते हैं:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

जिसे किसी भी स्ट्रिंग से आसानी से बुलाया जा सकता है:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

आउटपुट:

दोस्ताना मामले में मेरी पागल पास्कल केस वाक्य को बदलें

यह कस्टम गुण बनाने वाले घरों के चारों तरफ चल रहा है और उन्हें अपने एम्स में जोड़ रहा है या लुकअप टेबल का उपयोग करके एक दोस्ताना स्ट्रिंग के साथ एनम वैल्यू से शादी करने के लिए और अपने सभी के स्वयं के प्रबंधन का सर्वोत्तम उपयोग कर सकता है और किसी भी पास्कल केस स्ट्रिंग पर इस्तेमाल किया जा सकता है जो असीम है अधिक पुन: प्रयोज्य बेशक, यह आपके समाधान से प्रदान करने वाले आपके enum की तुलना में एक अलग दोस्ताना नाम रखने की अनुमति नहीं देता है।

यद्यपि अधिक जटिल परिदृश्यों के लिए हालांकि मैं आपके मूल समाधान की तरह करता हूं। आप अपना समाधान एक कदम आगे ले जा सकते हैं और अपने GetStringValue को अपने enum की एक विस्तार विधि बना सकते हैं और फिर आपको इसे संदर्भित करने की आवश्यकता नहीं होगी जैसे StringEnum.GetStringValue ...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

फिर आप अपने enum उदाहरण से सीधे इसे आसानी से एक्सेस कर सकते हैं:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());

आपके प्रश्न में आपने कभी नहीं कहा था कि आपको वास्तव में कहीं भी enum के संख्यात्मक मूल्य की आवश्यकता है।

यदि आपको टाइप स्ट्रिंग की एक enum की आवश्यकता नहीं है (जो एक अभिन्न प्रकार नहीं है तो enum का आधार नहीं हो सकता है) यहां एक तरीका है:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

आप इसे संदर्भित करने के लिए enum के समान वाक्यविन्यास का उपयोग कर सकते हैं

if (bla == AuthenticationMethod.FORMS)

यह संख्यात्मक मानों (संख्याओं के बजाय तारों की तुलना) की तुलना में थोड़ा धीमा होगा लेकिन प्लस तरफ यह स्ट्रिंग तक पहुंचने के लिए प्रतिबिंब (धीमी) का उपयोग नहीं कर रहा है।


जब मुझे इस समस्या का सामना करना पड़ता है, तो कुछ ऐसे प्रश्न हैं जिन्हें मैं पहले जवाब खोजने का प्रयास करता हूं:

  • क्या मेरे enum के नाम उद्देश्य के लिए पर्याप्त रूप से अनुकूल हैं, या क्या मुझे दोस्ताना प्रदान करने की ज़रूरत है?
  • क्या मुझे राउंड-ट्रिप करने की ज़रूरत है? यही है, क्या मुझे पाठ मूल्यों को लेने और उन्हें enum मानों में पार्स करने की आवश्यकता होगी?
  • क्या यह मेरी परियोजना में कई enums के लिए कुछ करने की ज़रूरत है, या सिर्फ एक?
  • मैं इस जानकारी को किस प्रकार के यूआई तत्व प्रस्तुत करूँगा - विशेष रूप से, क्या मैं यूआई के लिए बाध्यकारी होगा, या संपत्ति शीट का उपयोग करूँगा?
  • क्या इसे स्थानीयकरण योग्य होने की आवश्यकता है?

ऐसा करने का सबसे आसान तरीका Enum.GetValue (और Enum.Parse का उपयोग करके राउंड-ट्रिपिंग का समर्थन Enum.Parse ) के साथ है। स्टीव मिचैम यूआई बाइंडिंग का समर्थन करने के लिए सुझाव देता है, क्योंकि यह अक्सर TypeConverter बनाने के लायक है। (जब आप प्रॉपर्टी शीट्स का उपयोग कर रहे हैं, तो TypeConverter बनाना जरूरी नहीं है, जो प्रॉपर्टी शीट्स के बारे में अच्छी चीजों में से एक है। हालांकि भगवान जानता है कि उनके पास अपने स्वयं के मुद्दे हैं।)

सामान्य रूप से, यदि उपरोक्त प्रश्नों के उत्तर बताते हैं कि काम नहीं करेगा, तो मेरा अगला चरण एक स्थिर Dictionary<MyEnum, string> , या संभवतः एक Dictionary<Type, Dictionary<int, string>> बनाना और पॉप्युलेट करना है। मैं इंटरमीडिएट सजाने-द-कोड-साथ-एट्रिब्यूट्स चरण को छोड़ देता हूं क्योंकि आमतौर पर पाइक के नीचे क्या आ रहा है, तैनाती के बाद अनुकूल मूल्यों को बदलने की आवश्यकता होती है (अक्सर, लेकिन हमेशा स्थानीयकरण के कारण नहीं)।


बस ToString() विधि का उपयोग करें

public enum any{Tomato=0,Melon,Watermelon}

स्ट्रिंग Tomato संदर्भ देने के लिए, बस उपयोग करें

any.Tomato.ToString();

मुझे वास्तव में जैकब Šturc का जवाब पसंद है, लेकिन यह कमी है कि आप इसे स्विच-केस कथन के साथ उपयोग नहीं कर सकते हैं। यहां उनके उत्तर का थोड़ा संशोधित संस्करण है जिसका उपयोग स्विच स्टेटमेंट के साथ किया जा सकता है:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

तो आपको Jakub Šturc के उत्तर के सभी लाभ मिलते हैं, साथ ही हम इसका उपयोग स्विच स्टेटमेंट के साथ भी कर सकते हैं:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}

मैं System.ComponentModel नामस्थान से विवरण विशेषता का उपयोग करता हूं। बस enum को सजाने के लिए और फिर इसे पुनर्प्राप्त करने के लिए इस कोड का उपयोग करें:

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
        {
            Type type = enumerationValue.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
            }

            //Tries to find a DescriptionAttribute for a potential friendly name
            //for the enum
            MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    //Pull out the description value
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }
            //If we have no description attribute, just return the ToString of the enum
            return enumerationValue.ToString();

        }

उदहारण के लिए:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

यह कोड अच्छी तरह से enums के लिए पूरा करता है जहां आपको "दोस्ताना नाम" की आवश्यकता नहीं होती है और enum के .ToString () को वापस कर देगा।


मैं इसे नीचे उद्धृत पद पर टिप्पणी के रूप में पोस्ट करना चाहता था लेकिन ऐसा नहीं कर सका क्योंकि मेरे पास पर्याप्त प्रतिनिधि नहीं है - इसलिए कृपया नीचे मत दें। कोड में एक त्रुटि थी और मैं इसे इस समाधान का उपयोग करने की कोशिश करने वाले व्यक्तियों को इंगित करना चाहता था:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

होना चाहिए

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

प्रतिभाशाली!


मैं एक विस्तार विधि का उपयोग करता हूं:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

अब enum को सजाने के साथ:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

जब तुमने फोन किया

AuthenticationMethod.FORMS.ToDescription() "FORMS" AuthenticationMethod.FORMS.ToDescription() आपको "FORMS" मिलेगा।


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

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

enum:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

उपयोग (जहां o.OrderType enum के समान नाम वाली एक संपत्ति है):

o.OrderType.GetDescription()

जो मुझे वास्तविक एनम वैल्यू न्यूकार्ड और रीफिल के बजाय "नया कार्ड" या "रीलोड" की स्ट्रिंग देता है।


विधि का प्रयोग करें

Enum.GetName(Type MyEnumType,  object enumvariable)  

जैसा कि (Assume Shipper एक परिभाषित एनम है)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

एनम कक्षा पर भी जांच के लायक अन्य स्थिर तरीकों का एक गुच्छा है ...


type-safe-enum पैटर्न का प्रयास करें।

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

अद्यतन स्पष्ट (या निहित) प्रकार रूपांतरण द्वारा किया जा सकता है

  • मैपिंग के साथ स्थिर क्षेत्र जोड़ना

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • एनबी उदाहरण के लिए कि "एनम सदस्य" फ़ील्ड का प्रारंभिक उदाहरण कन्स्ट्रक्टर को कॉल करते समय NullReferenceException नहीं फेंकता है, तो सुनिश्चित करें कि डिक्शनरी फ़ील्ड को अपनी कक्षा में "enum सदस्य" फ़ील्ड से पहले रखना सुनिश्चित करें। ऐसा इसलिए है क्योंकि स्थैतिक क्षेत्र प्रारंभकर्ताओं को घोषणा आदेश में और स्थिर कन्स्ट्रक्टर से पहले बुलाया जाता है, अजीब और जरूरी लेकिन भ्रमित स्थिति बनाते हैं कि सभी स्थिर क्षेत्रों को शुरू करने से पहले इंस्टेंस कन्स्ट्रक्टर को बुलाया जा सकता है, और स्थिर कन्स्ट्रक्टर कहने से पहले।
  • उदाहरण में कन्स्ट्रक्टर को इस मैपिंग को भरना

    instance[name] = this;
    
  • और उपयोगकर्ता परिभाषित प्रकार रूपांतरण ऑपरेटर जोड़ना

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    

मैं कीथ से सहमत हूं, लेकिन मैं वोट नहीं दे सकता (अभी तक)।

मैं वही चीज़ लौटने के लिए एक स्थिर विधि और स्विथ स्टेटमेंट का उपयोग करता हूं जो मैं चाहता हूं। डेटाबेस में मैं tinyint स्टोर करता हूं और मेरा कोड केवल वास्तविक enum का उपयोग करता है, इसलिए स्ट्रिंग UI आवश्यकताओं के लिए हैं। कई परीक्षणों के बाद इसने आउटपुट पर सबसे अच्छा प्रदर्शन और अधिक नियंत्रण किया।

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

हालांकि, कुछ खातों से, यह एक संभावित रखरखाव दुःस्वप्न और कुछ कोड गंध की ओर जाता है। मैं लंबे समय तक और बहुत सारे enums, या जो अक्सर बदलते हैं, के लिए एक नजर रखने की कोशिश करते हैं। अन्यथा, यह मेरे लिए एक अच्छा समाधान रहा है।


A lot of great answers here but in my case did not solve what I wanted out of an "string enum", which was:

  1. Usable in a switch statement eg switch(myEnum)
  2. Can be used in function parameters eg foo(myEnum type)
  3. Can be referenced eg myEnum.FirstElement
  4. I can use strings eg foo("FirstElement") == foo(myEnum.FirstElement)

1,2 & 4 can actually be solved with a C# Typedef of a string (since strings are switchable in c#)

3 can be solved by static const strings. So if you have the same needs, this is the simplest approach:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

This allows for example:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

तथा

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Where CreateType can be called with a string or a type. However the downside is that any string is automatically a valid enum , this could be modified but then it would require some kind of init function...or possibly make they explicit cast internal?

Now if an int value was important to you (perhaps for comparison speed), you could use some ideas from Jakub Šturc fantastic answer and do something a bit crazy, this is my stab at it:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

but of course "Types bob = 4;" would be meaningless unless you had initialized them first which would sort of defeat the point...

But in theory TypeA == TypeB would be quicker...


If I'm understanding you correctly, you can simply use .ToString() to retrieve the name of the enum from the value (Assuming it's already cast as the Enum); If you had the naked int (lets say from a database or something) you can first cast it to the enum. Both methods below will get you the enum name.

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

Keep in mind though, the second technique assumes you are using ints and your index is 1 based (not 0 based). The function GetNames also is quite heavy by comparison, you are generating a whole array each time it's called. As you can see in the first technique, .ToString() is actually called implicitly. Both of these are already mentioned in the answers of course, I'm just trying to clarify the differences between them.


If you think about the problem we're trying to solve, it's not an enum we need at all. We need an object that allows a certain number of values to be associated with eachother; in other words, to define a class.

Jakub Šturc's type-safe enum pattern is the best option I see here.

Look at it:

  • It has a private constructor so only the class itself can define the allowed values.
  • It is a sealed class so values can't be modifed through inheritence.
  • It is type-safe, allowing your methods to require only that type.
  • There is no reflection performance hit incurred by accessing the values.
  • And lastly, it can be modified to associate more than two fields together, for example a Name, Description, and a numeric Value.

Option 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

और फिर

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

Option 2:

public enum AuthenticationMethod
{
        FORMS = 1,
        WINDOWSAUTHENTICATION = 2,
        SINGLESIGNON = 3
}

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}


When I am in a situation like that I propose the solution below.

And as a consuming class you could have

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

And using a bidirectional dictionary: Based on this ( https://.com/a/255638/986160 ) assuming that the keys will be associated with single values in the dictionary and similar to ( https://.com/a/255630/986160 ) but a bit more elegant. This dictionary is also enumerable and you can go back and forth from ints to strings. Also you don't have to have any string in your codebase with the exception of this class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}





enums