c# شرح تمثيل سلسلة التعداد




struct in c# (20)

أستخدم طريقة إضافة:

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" .

https://code.i-harness.com

لدي التعداد التالي:

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

ولكن المشكلة هي أنني أحتاج إلى كلمة "FORMS" عندما أطلب AuthenticationMethod.FORMS وليس المعرّف 1.

لقد وجدت الحل التالي لهذه المشكلة ( link ):

أولاً ، أحتاج إلى إنشاء سمة مخصصة تسمى "StringValue":

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
}

وبالطبع أحتاج إلى شيء لاسترداد ذلك StringValue:

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);

حسناً ، كل هذه الأشياء تعمل مثل السحر ، لكني أجد الكثير من العمل. كنت أتساءل إذا كان هناك حل أفضل لهذا.

كما أنني حاولت شيئا مع قاموس وخصائص ثابتة ولكن ذلك لم يكن أفضل سواء.


أستخدم مزيجًا من العديد من الاقتراحات أعلاه ، مع بعض التخزين المؤقت. الآن ، حصلت على فكرة من بعض التعليمات البرمجية التي وجدت في مكان ما على شبكة الإنترنت ، ولكن لا أستطيع تذكر أين حصلت عليه أو العثور عليه. لذلك إذا وجد أي شخص شيئًا مشابهًا ، فيُرجى التعليق على الإسناد.

على أي حال ، يتضمن الاستخدام محولات النوع ، لذلك إذا كنت ملزماً لـ UI "تعمل فقط". يمكنك تمديد مع نمط Jakub للبحث عن رمز سريع عن طريق تهيئة من نوع المحول إلى أساليب ثابتة.

قد يبدو استخدام القاعدة هكذا

[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 class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}


إذا جئت إلى هنا لتتطلع إلى تطبيق "التعداد" البسيط ولكن قيمه عبارة عن سلاسل بدلاً من النتوءات ، فإليك أبسط حل:

    public sealed class MetricValueList
    {
        public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
        public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
    }

التنفيذ:

var someStringVariable = MetricValueList.Brand;

باعتباري معظمكم ، أعجبتني الإجابة التي اختارتها Jakub Šturc ، لكنني أيضًا أكره حقًا نسخ الشفرة ، ومحاولة القيام بها بأقل قدر ممكن.

لذلك قررت أنني أردت الحصول على فئة EnumBase التي توارث بها معظم الوظائف / مدمجة ، مما يتركني للتركيز على المحتوى بدلاً من السلوك.

تعتمد المشكلة الأساسية في هذا الأسلوب على حقيقة أنه على الرغم من أن قيم التعداد هي مثيلات آمنة من النوع ، يكون التفاعل مع التطبيق الثابت لنوع فئة التعداد. لذا ، بمساعدة القليل من سحر الأدوية الجنسية ، أعتقد أني حصلت في النهاية على المزيج الصحيح. نأمل أن يجد شخص ما هذا مفيدًا كما فعلت.

سأبدأ مع مثال ياكوب ، ولكن باستخدام الميراث والأدوية:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    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)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

وها هي الطبقة الأساسية:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it's own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}

جرب نمط 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 عند استدعاء مُنشئ المثيل ، تأكد من وضع حقل القاموس قبل حقول "عضو التعداد" في الفصل الدراسي. ويرجع ذلك إلى أنه يتم استدعاء ألقاب الحقل الثابت في ترتيب تعريف ، وقبل منشئ ثابت ، إنشاء الموقف الغريب والضروري لكن المربك الذي يمكن استدعاء مُنشئ المثيل قبل أن تتم تهيئة كافة الحقول الثابتة ، وقبل استدعاء المُنشئ الاستاتيكي.
  • ملء هذا التعيين على سبيل المثال منشئ

    instance[name] = this;
    
  • وإضافة عامل تحويل نوع المعرفة من قبل المستخدم

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

حل بسيط جدا لهذا مع. صافي 4.0 وما فوق. لا يوجد رمز آخر مطلوب.

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

للحصول على السلسلة حول الاستخدام فقط:

MyStatus.Active.ToString("f");

أو

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

ستكون القيمة "نشطة" أو "مؤرشفة".

لمشاهدة تنسيقات السلسلة المختلفة ("f" من أعلى) عند استدعاء Enum.ToString انظر صفحة سلاسل عمليات التعداد هذه


عندما أواجه هذه المشكلة ، هناك بعض الأسئلة التي أحاول أن أجيب عليها أولاً:

  • هل أسماء قيم التعداد الخاصة بي ملائمة بشكل كافٍ لهذا الغرض ، أم أحتاج إلى توفير قيم أكثر صداقة؟
  • هل أحتاج إلى رحلة ذهاب وعودة؟ أي ، هل سأحتاج إلى أخذ قيم نصية وتحليلها في قيم التعداد؟
  • هل هذا شيء أحتاج إلى القيام به للعديد من التعدادات في مشروعي ، أو واحد فقط؟
  • أي نوع من عناصر واجهة المستخدم سوف أقوم بتقديم هذه المعلومات - على وجه الخصوص ، هل سأكون ملزمة لواجهة المستخدم ، أو باستخدام أوراق الملكية؟
  • هل هذا يحتاج إلى أن يكون قابلاً للتحديث؟

إن أبسط طريقة للقيام بذلك هي Enum.GetValue (ودعم round-tripping باستخدام Enum.Parse ). كما أنه في كثير من الأحيان يستحق بناء TypeConverter ، كما يقترح ستيف ميتشام ، لدعم ربط واجهة المستخدم. (ليس من الضروري إنشاء TypeConverter عند استخدام أوراق الملكية ، وهي واحدة من الأشياء اللطيفة حول أوراق الملكية. على الرغم من أن اللورد يعرف أن لديه TypeConverter الخاصة.)

بشكل عام ، إذا كانت الإجابات على الأسئلة المذكورة أعلاه تشير إلى أن هذا لن ينجح ، فإن الخطوة التالية هي إنشاء Dictionary<MyEnum, string> ثابت Dictionary<MyEnum, string> ، أو Dictionary<MyEnum, string> ، أو ربما Dictionary<Type, Dictionary<int, string>> . أميل إلى تخطي الخطوة المتوسطة لتزيين-رمز-مع-الصفات لأن ما يأتي عادة أسفل البايك القادم هو الحاجة إلى تغيير القيم الودية بعد النشر (في كثير من الأحيان ، ولكن ليس دائماً ، بسبب التعريب).


فقط استخدم الأسلوب ToString()

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

للإشارة إلى سلسلة Tomato ، استخدم فقط

any.Tomato.ToString();

كيف حلت هذا كطريقة تمديد:

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();
}

التعداد:

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

الاستخدام (حيث o.OrderType عبارة عن خاصية لها نفس الاسم مثل التعداد):

o.OrderType.GetDescription()

الذي يعطيني سلسلة من "البطاقة الجديدة" أو "إعادة تحميل" بدلاً من قيمة التضمين الفعلية NewCard و Refill.


لسوء الحظ ، فإن التفكير في الحصول على سمات على التعداد بطيء جدًا:

راجع هذا السؤال: أي شخص يعرف طريقة سريعة للوصول إلى سمات مخصصة على قيمة التعداد؟

.ToString() بطيء جدًا على التعداد أيضًا.

يمكنك كتابة طرق الإضافة للتعداد على الرغم من:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

هذا ليس رائعًا ، ولكنه سيكون سريعًا ولا يتطلب انعكاسًا للسمات أو اسم الحقل.

تحديث C # 6

إذا كان بإمكانك استخدام C # 6 ، فإن مشغل nameof الجديد يعمل على nameof(MyEnum.WINDOWSAUTHENTICATION) ، لذلك سيتم تحويل nameof(MyEnum.WINDOWSAUTHENTICATION) إلى "WINDOWSAUTHENTICATION" في وقت التحويل البرمجي ، مما يجعله أسرع طريقة للحصول على أسماء التعداد.

لاحظ أن هذا سيحول التعداد الصريح إلى ثابت مضمن ، لذلك لا يعمل مع التعدادات التي لديك في المتغير. وبالتالي:

nameof(AuthenticationMethod.FORMS) == "FORMS"

لكن...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

يمكنك الرجوع إلى الاسم بدلاً من القيمة باستخدام ToString ()

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

الوثائق هنا:

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

... وإذا قمت بتسمية التعدادات الخاصة بك في Pascal Case (كما أفعل - مثل ThisIsMyEnumValue = 1 إلخ) ، يمكنك استخدام تعبير عادي بسيط لطباعة النموذج المألوف:

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

والتي يمكن استدعاؤها بسهولة من أي سلسلة:

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

المخرجات:

تحويل My Crazy Pascal Case Sentence إلى حالة ودية

هذا يحفظ تشغيل جميع أنحاء المنازل التي تخلق سمات مخصصة وتعلقها على التعدادات أو استخدام جداول البحث لتتزوج قيمة التعداد مع سلسلة ودية وأفضل ما في كل ذلك إدارة الذات ويمكن استخدامها على أي سلسلة باسكال القضية التي لا نهاية أكثر قابلة لإعادة الاستخدام. بالطبع ، لا يسمح لك أن يكون لديك اسم مألوف مختلف عن التعداد الذي تقدمه حلولك.

أنا أحب الحل الأصلي الخاص بك على الرغم من سيناريوهات أكثر تعقيدا رغم ذلك. هل يمكن أن تأخذ الحل الخاص بك خطوة أخرى إلى الأمام وجعل GetStringValue طريقة تمديد التعداد الخاص بك ومن ثم لن تحتاج إلى الرجوع إليه مثل 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;
}

يمكنك بعد ذلك الوصول إليه بسهولة من مثال التعداد:

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

يمكنني استخدام السمة الوصف من مساحة الاسم System.ComponentModel. ببساطة قم بتزيين التعداد ثم استخدم هذا الرمز لاسترداده:

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
}

هذا الرمز يلائم بشكل جيد التعدادات حيث لا تحتاج إلى "اسم مألوف" وسيعود فقط .ToString () من التعداد.


أتفق مع كيث ، لكن لا يمكنني التصويت (حتى الآن).

أنا استخدم طريقة ثابتة وبيان سويث للعودة بالضبط ما أريد. في قاعدة البيانات I تخزين tinyint ويستخدم رمز فقط التعداد الفعلي ، بحيث يتم السلاسل لمتطلبات واجهة المستخدم. بعد إجراء العديد من الاختبارات ، أدى ذلك إلى تحقيق أفضل أداء وأفضل تحكم في الإخراج.

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

ومع ذلك ، من خلال بعض الحسابات ، وهذا يؤدي إلى كابوس الصيانة المحتملة وبعض رائحة الكود. أحاول أن أبقى عينًا على التعدادات الطويلة والكثير من التعدادات ، أو تلك التي تتغير كثيرًا. خلاف ذلك ، كان هذا حلا رائعا بالنسبة لي.


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