C#string枚举

我有以下枚举:

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

然而,问题是当我要求AuthenticationMethod.FORMS而不是id 1时,我需要“FORMS”这个词。

我已经find了这个问题的下面的解决scheme( 链接 ):

首先,我需要创build一个名为“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值。 我可以像这样使用它:

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

好吧现在所有这些工作都像一个魅力,但我觉得这是一个很大的工作。 我想知道是否有更好的解决scheme。

我也尝试了一些字典和静态属性,但那也不是更好。

尝试使用types安全枚举模式。

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

更新显式(或隐式)types转换可以通过

  • 添加静态字段与映射

     private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>(); 
    • nb为了在调用实例构造函数时“enum member”字段的初始化不会抛出NullReferenceException,请务必将Dictionary字段放在类中的“enum member”字段之前。 这是因为静态字段初始化程序以声明顺序调用,并且在静态构造函数之前创build了奇怪的必要但令人困惑的情况,即在所有静态字段被初始化之前以及在调用静态构造函数之前调用实例构造函数。
  • 在实例构造函数中填充这个映射

     instance[name] = this; 
  • 并添加用户定义的types转换运算符

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

使用方法

 Enum.GetName(Type MyEnumType, object enumvariable) 

如(假设Shipper是一个定义的枚举)

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

在Enum类中还有一些其他静态方法也值得研究…

您可以通过使用ToString()来引用名称而不是值

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

文档在这里:

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

…如果你在Pascal Case中命名你的枚举(就像我这样 – 例如ThisIsMyEnumValue = 1等),那么你可以使用一个非常简单的正则expression式打印友好的forms:

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

这可以很容易地从任何string中调用:

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

输出:

将我的疯狂帕斯卡案件判决转换为友好案件

这可以节省运行周围的房屋创build自定义属性,并将它们附加到您的枚举或使用查找表结婚enum值与友好的string,最重要的是它是自我pipe理,可用于任何Pascal案例string是无限的更可重用。 当然,它不允许你有一个不同于你的解决scheme提供的枚举的友好名称。

尽pipe对于更复杂的场景,我确实喜欢你原来的解决scheme。 您可以进一步采取您的解决scheme,并使您的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()); 

不幸的是,在枚举上获得属性的reflection非常缓慢:

看到这个问题: 任何人都知道一个快速的方法来获得一个枚举值的自定义属性?

.ToString()在枚举上也很慢。

你可以写枚举的扩展方法,虽然:

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

这不是很好,但会很快,不需要reflection属性或字段名称。


C#6更新

如果你可以使用C#6,那么运算符的新nameof可以用于枚举了,所以nameof(MyEnum.WINDOWSAUTHENTICATION)将在编译时转换为"WINDOWSAUTHENTICATION" ,这是获取枚举名的最快方法。

请注意,这将显式枚举转换为内联常量,所以它不适用于variables中的枚举。 所以:

 nameof(AuthenticationMethod.FORMS) == "FORMS" 

但…

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

我使用扩展方法:

 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"

只需使用ToString()方法即可

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

要引用stringTomato ,只需使用

 any.Tomato.ToString(); 

我使用System.ComponentModel命名空间中的Description属性。 只需简单地装饰枚举,然后使用此代码来检索它:

 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()。

我真的很喜欢JakubŠturc的回答,但缺点是你不能用switch-case语句来使用它。 这是他的答案的一个稍微修改版本,可以用switch语句:

 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的答案的所有好处,另外我们可以像使用switch语句一样使用它:

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

使用.Net 4.0及以上版本的非常简单的解决scheme。 没有其他的代码是必要的。

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

要得到string,只需使用:

 MyStatus.Active.ToString("f"); 

要么

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

该值将是“活动”或“存档”。

我使用上述几个build议的组合,并结合一些caching。 现在,我从网上find的一些代码中得到了这个想法,但是我不记得我在哪里find它或find它。 所以,如果有人发现类似的东西,请评论属性。

无论如何,用法涉及types转换器,所以如果你绑定到用户界面,它只是“工作”。 您可以通过从types转换器初始化为静态方法来扩展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 } 

自定义枚举types转换器的代码如下所示:

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

}

我同意Keith的观点,但我还是不能投票。

我使用静态方法和swith语句来返回我想要的。 在数据库中我存储tinyint和我的代码只使用实际的枚举,所以这些string是UI的要求。 经过多次testing,这样可以获得最佳性能和对输出的最大控制。

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

但是,由于某些原因,这会导致可能的维护噩梦和一些代码异味。 我试着留意那些很长很多枚枚举的枚举,或者经常改变的枚举。 否则,这对我来说是一个很好的解决scheme。

就像你们中的大多数人一样,我真的很喜欢JakubŠturc所select的答案 ,但是我也非常讨厌复制粘贴代码,并尽可能less地尝试。

所以我决定我想要一个EnumBase类,其中大部分的function是inheritance/内置的,让我专注于内容而不是行为。

这种方法的主要问题是基于这样一个事实,即虽然枚举值是types安全的实例,但交互是与枚举类types的静态实现。 所以有了generics魔法的一点帮助,我想我终于得到了正确的组合。 希望有人认为这个和我一样有用。

我将从Jakub的例子开始,但使用inheritance和generics:

 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 } 

我如何解决这个扩展方法:

 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。

在你的问题你从来没有说过,你实际上需要任何地方的枚举的数值。

如果你不需要,只需要一个stringtypes的枚举(这不是一个整型,所以不能作为枚举的基础)这里是一个方法:

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

您可以使用与enum相同的语法来引用它

 if (bla == AuthenticationMethod.FORMS) 

它会比使用数字值(比较string而不是数字)慢一些,但在正面不使用reflection(慢)来访问string。

当我遇到这个问题时,有几个问题我试图find第一个答案:

  • 我的枚举值的名称是否足够友好的目的,还是我需要提供更友好的?
  • 我需要往返吗? 也就是说,我需要将文本值和parsing成枚举值?
  • 这是我需要为我的项目中的许多枚举做什么,或者只是一个?
  • 我将在哪些types的UI元素中展示这些信息 – 特别是,我将绑定到UI还是使用属性表?
  • 这是否需要本地化?

最简单的方法是使用Enum.GetValue (并支持使用Enum.Parse进行Enum.Parse )。 像Steve Mitcham所build议的那样,build立一个TypeConverter也经常值得支持UI绑定。 (当你使用属性表时,没有必要build立一个TypeConverter ,这是属性表的TypeConverter之一,虽然上帝知道他们有自己的问题)。

一般来说,如果上述问题的答案表明不起作用,那么我的下一步就是创build并填充一个静态的Dictionary<MyEnum, string> ,或者可能是一个Dictionary<Type, Dictionary<int, string>> 。 我倾向于跳过中间装饰代码与属性的步骤,因为接下来派克通常会在部署之后改变友好值(通常,但并非总是因为本地化)。

我想张贴这个作为对下面引用的post的评论,但不能因为我没有足够的代表 – 所以请不要倒票。 代码包含一个错误,我想指出这个试图使用这个解决scheme的个人:

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

高明!

如果你来这里想要实现一个简单的“枚举”,但其值是string而不是整数,这里是最简单的解决scheme:

  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; 

选项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()); 

选项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"); } } 

如果你想想我们要解决的问题,那不是我们需要的枚举。 我们需要一个允许一定数量的值与对方相关联的对象; 换句话说,定义一个类。

JakubŠturc的types安全的枚举模式是我在这里看到的最好的select。

看它:

  • 它有一个私有的构造函数,所以只有类本身可以定义允许的值。
  • 这是一个密封的类,所以值不能通过inheritance来修改。
  • 这是types安全的,允许你的方法只需要这种types。
  • 访问值没有reflection性能的影响。
  • 最后,可以将其修改为将两个以上的字段关联在一起,例如Name,Description和numeric Value。

我的变种

 public struct Colors { private String current; private static string red = "#ff0000"; private static string green = "#00ff00"; private static string blue = "#0000ff"; private static IList<String> possibleColors; public static Colors Red { get { return (Colors) red; } } public static Colors Green { get { return (Colors) green; } } public static Colors Blue { get { return (Colors) blue; } } static Colors() { possibleColors = new List<string>() {red, green, blue}; } public static explicit operator String(Colors value) { return value.current; } public static explicit operator Colors(String value) { if (!possibleColors.Contains(value)) { throw new InvalidCastException(); } Colors color = new Colors(); color.current = value; return color; } public static bool operator ==(Colors left, Colors right) { return left.current == right.current; } public static bool operator !=(Colors left, Colors right) { return left.current != right.current; } public bool Equals(Colors other) { return Equals(other.current, current); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (obj.GetType() != typeof(Colors)) return false; return Equals((Colors)obj); } public override int GetHashCode() { return (current != null ? current.GetHashCode() : 0); } public override string ToString() { return current; } } 

Code looks a bit ugly, but usages of this struct are pretty presentative.

 Colors color1 = Colors.Red; Console.WriteLine(color1); // #ff0000 Colors color2 = (Colors) "#00ff00"; Console.WriteLine(color2); // #00ff00 // Colors color3 = "#0000ff"; // Compilation error // String color4 = Colors.Red; // Compilation error Colors color5 = (Colors)"#ff0000"; Console.WriteLine(color1 == color5); // True Colors color6 = (Colors)"#00ff00"; Console.WriteLine(color1 == color6); // False 

Also, I think, if a lot of such enums required, code generation (eg T4) might be used.

for me, the pragmatic approach is class inside class, sample:

 public class MSEModel { class WITS { public const string DATE = "5005"; public const string TIME = "5006"; public const string MD = "5008"; public const string ROP = "5075"; public const string WOB = "5073"; public const string RPM = "7001"; ... } 

Here is yet another way to accomplish the task of associating strings with enums:

 struct DATABASE { public enum enums {NOTCONNECTED, CONNECTED, ERROR} static List<string> strings = new List<string>() {"Not Connected", "Connected", "Error"}; public string GetString(DATABASE.enums value) { return strings[(int)value]; } } 

This method is called like this:

 public FormMain() { DATABASE dbEnum; string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED); } 

You can group related enums in their own struct. Since this method uses the enum type, you can use Intellisense to display the list of enums when making the GetString() call.

You can optionally use the new operator on the DATABASE struct. Not using it means the strings List is not allocated until the first GetString() call is made.

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.

old post but…

The answer to this may actually be very simple. Use Enum.ToString() function

There are 6 overloads of this function, you can use Enum.Tostring("F") or Enum.ToString() to return the string value. No need to bother with anything else. Here is a working Demo

Note that this solution may not work for all compilers ( this demo does not work as expected ) but at least it works for the latest compiler.

based on the MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx

 foreach (string str in Enum.GetNames(typeof(enumHeaderField))) { Debug.WriteLine(str); } 

str will be the names of the fields

Well, after reading all of the above I feel that the guys have over complicated the issue of transforming enumerators into strings. I liked the idea of having attributes over enumerated fields but i think that attributes are mainly used for Meta-data, but in your case i think that all you need is some sort of localization.

 public enum Color { Red = 1, Green = 2, Blue = 3} public static EnumUtils { public static string GetEnumResourceString(object enumValue) { Type enumType = enumValue.GetType(); string value = Enum.GetName(enumValue.GetType(), enumValue); string resourceKey = String.Format("{0}_{1}", enumType.Name, value); string result = Resources.Enums.ResourceManager.GetString(resourceKey); if (string.IsNullOrEmpty(result)) { result = String.Format("{0}", value); } return result; } } 

Now if we try to call the above method we can call it this way

 public void Foo() { var col = Color.Red; Console.WriteLine (EnumUtils.GetEnumResourceString (col)); } 

All you need to do is just create a resource file containing all the enumerator values and the corresponding strings

Resource Name Resource Value
Color_Red My String Color in Red
Color_Blue Blueeey
Color_Green Hulk Color

What is actually very nice about that is that it will be very helpful if you need your application to be localized, since all you need to do is just create another resource file with your new language! and Voe-la!

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

作为一个消费类,你可以拥有

 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://stackoverflow.com/a/255638/986160 ) assuming that the keys will be associated with single values in the dictionary and similar to ( https://stackoverflow.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(); } } } 

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…

Use object Enum.Parse(System.Type enumType, string value, bool ignoreCase); got it from http://blogs.msdn.com/b/tims/archive/2004/04/02/106310.aspx

My answer, working on @user29964 's answer (which is by far the simplest and closest to a Enum) is

  public class StringValue : System.Attribute { private string _value; public StringValue(string value) { _value = value; } public string Value { get { return _value; } } public static string GetStringValue(Enum Flagvalue) { Type type = Flagvalue.GetType(); string[] flags = Flagvalue.ToString().Split(',').Select(x => x.Trim()).ToArray(); List<string> values = new List<string>(); for (int i = 0; i < flags.Length; i++) { FieldInfo fi = type.GetField(flags[i].ToString()); StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[]; if (attrs.Length > 0) { values.Add(attrs[0].Value); } } return String.Join(",", values); } 

用法

 [Flags] public enum CompeteMetric { /// <summary> /// u /// </summary> [StringValue("u")]//Json mapping Basic_UniqueVisitors = 1 //Basic , /// <summary> /// vi /// </summary> [StringValue("vi")]//json mapping Basic_Visits = 2// Basic , /// <summary> /// rank /// </summary> [StringValue("rank")]//json mapping Basic_Rank = 4//Basic } 

  CompeteMetric metrics = CompeteMetric.Basic_Visits | CompeteMetric.Basic_Rank; string strmetrics = StringValue.GetStringValue(metrics); 

this will return "vi,rank"