提问



我有以下枚举:


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


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


我找到了这个问题的以下解决方案(链接):[88]


首先,我需要创建一个名为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);


好的,现在所有这些都像魅力一样,但我发现它做了很多工作。我想知道是否有更好的解决方案。


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

最佳参考


尝试使用type-safe-enum模式。[89]


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



    • n.b。为了使枚举成员字段的初始化在调用实例构造函数时不会抛出NullReferenceException,请确保将Dictionary字段放在类中的enum member字段之前。这是因为静态字段初始化器是在声明顺序中调用,在静态构造函数之前,创建奇怪且必要但令人困惑的情况,即在初始化所有静态字段之前,以及在调用静态构造函数之前,可以调用实例构造函数。


  • 在实例构造函数中填充此映射


    instance[name] = this;
    

  • 并添加用户定义的类型转换运算符[90]


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


其它参考1


使用方法


Enum.GetName(Type MyEnumType,  object enumvariable)  


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


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


Enum类还有很多其他静态方法值得研究......

其它参考2


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


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


文档在这里:


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


...如果你在Pascal Case中命名你的枚举(正如我所做的那样 - 例如ThisIsMyEnumValue=1等),那么你可以使用一个非常简单的正则表达式来打印友好的形式:


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


可以从任何字符串轻松调用:


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


输出:



  将我疯狂的帕斯卡案句转换为友好案例



这样可以节省在房屋周围的运行,创建自定义属性并将它们附加到您的枚举或使用查找表将枚举值与友好字符串结合,最重要的是它自我管理并可用于任何Pascal Case字符串无限可重用。当然,它不允许你有一个不同的友好名称,而不是你的解决方案提供的枚举。


虽然对于更复杂的场景,我确实喜欢你的原始解决方案。您可以更进一步地使用您的解决方案,并使您的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());

其它参考3


不幸的是,在枚举上获取属性的反射非常慢:


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


.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)将在编译时转换为"WINDOWSAUTHENTICATION",使其最快得到枚举名称的方法。


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


nameof(AuthenticationMethod.FORMS) == "FORMS"


但...


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

其它参考4


我使用扩展方法:


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"

其它参考5


只需使用ToString()方法


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


要引用字符串Tomato,只需使用


any.Tomato.ToString();

其它参考6


我使用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()。

其它参考7


使用.Net 4.0及更高版本的解决方案非常简单。不需要其他代码。


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


要获取有关使用的字符串:


MyStatus.Active.ToString("f");


要么


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


该值将为Activity或已存档。


要在调用Enum.ToString时查看不同的字符串格式(上面的f),请参阅此枚举格式字符串页面[93]

其它参考8


我真的很喜欢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;      
}

其它参考9


我使用了上面几个建议的组合,并结合了一些缓存。现在,我从网上某处找到的一些代码中得到了这个想法,但我既不记得我在哪里找到它或者找到它。因此,如果有人发现类似的内容,请对归因进行评论。


无论如何,用法涉及类型转换器,所以如果你绑定到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);
    }
}


}

其它参考10


就像大多数人一样,我非常喜欢JakubŠturc选择的答案,但我也非常讨厌复制粘贴代码,并尽可能少地尝试。


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


这种方法的主要问题是基于以下事实:虽然Enum值是类型安全的实例,但是交互是与Enum类类型的Static实现。
因此,在仿制魔术的帮助下,我想我终于得到了正确的组合。
希望有人发现这和我一样有用。


我将从Jakub的例子开始,但是使用继承和泛型:


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
}

其它参考11


我同意基思,但我还不能投票。


我使用静态方法和swith语句来准确返回我想要的内容。在数据库中我存储tinyint,我的代码只使用实际的枚举,因此字符串用于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;
     }
}


但是,根据某些说法,这会导致可能的维护噩梦和一些代码味道。我试着留意那些长篇大论的词汇,或者经常变化的词汇。否则,这对我来说是一个很好的解决方案。

其它参考12


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


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。

其它参考13


在你的问题中,你从未说过你实际上需要枚举的数值。


如果你不这样做,只需要一个类型字符串的枚举(这不是一个整数类型,所以不能作为枚举的基础)这里是一种方式:


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


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


if (bla == AuthenticationMethod.FORMS)


它会比使用数值(比较字符串而不是数字)慢一点,但在正面,它不使用反射(慢)来访问字符串。

其它参考14


如果您来到这里寻求实现一个简单的Enum但其值是字符串而不是整数,这是最简单的解决方案:


    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;

其它参考15


当我遇到这个问题时,有几个问题我试图先找到答案:



  • 我的枚举值的名称是否足够友好,或者我是否需要提供更友好的名称?

  • 我需要往返吗?也就是说,我需要获取文本值并将它们解析为枚举值吗?

  • 这是我需要为我的项目中的许多枚举做些什么,还是只有一个?

  • 我将在哪些UI元素中呈现此信息 - 特别是,我是否会绑定到UI或使用属性表?

  • 这是否需要可本地化?



最简单的方法是使用Enum.GetValue(并使用Enum.Parse支持往返)。正如Steve Mitcham建议的那样,建立TypeConverter也常常值得支持UI绑定。(当你使用属性表时,没有必要建立TypeConverter,这是其中之一关于物业单的好处。虽然上帝知道他们有自己的问题。)


一般来说,如果上述问题的答案表明不会起作用,我的下一步就是创建并填充静态Dictionary<MyEnum, string>,或者可能Dictionary<Type, Dictionary<int, string>>。我倾向于跳过中间体decorate-the-code-with-attributes步骤因为接下来通常会出现在长矛上的是需要在部署后更改友好值(通常,但并非总是如此,因为本地化)。

其它参考16


我想发布这个作为对下面引用的帖子的评论,但不能因为我没有足够的代表 - 所以请不要投票。代码中包含错误,我想指出这个问题。使用此解决方案:



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


高明!

其它参考17


我的变种


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


代码看起来有点难看,但这个结构的用法非常具有代表性。


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


另外,我认为,如果需要很多这样的枚举,可能会使用代码生成(例如T4)。

其它参考18


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

其它参考19


如果你想到我们试图解决的问题,那根本就不是我们需要的一个问题。我们需要一个允许一定数量的值相互关联的对象;换句话说,定义一个类。


JakubŠturc的类型安全枚举模式是我在这里看到的最佳选择。


看它:



  • 它有一个私有构造函数,因此只有类本身才能定义允许的值。

  • 这是一个密封的类,因此不能通过继承修改值。

  • 它是类型安全的,允许您的方法只需要该类型。

  • 访问值时未发生任何反射性能损失。

  • 最后,可以修改它以将两个以上的字段关联在一起,例如名称,描述和数值。


其它参考20


对我来说,实用的方法是类里面的类,示例:


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

其它参考21


这是完成将字符串与枚举相关联的另一种方法:


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


这个方法的调用方式如下:


public FormMain() {
    DATABASE dbEnum;

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


您可以在自己的结构中对相关的枚举进行分组。由于此方法使用枚举类型,因此您可以使用Intellisense在进行GetString()调用时显示枚举列表。


您可以选择在DATABASE结构上使用new运算符。不使用它意味着在第一次GetString()调用之前不会分配字符串List

其它参考22


如果我正确地理解你,你可以简单地使用.ToString()从值中检索枚举的名称(假设它已经被强制转换为枚举);
如果您有裸体int(比如说从数据库或其他东西),您可以先将其转换为枚举。
下面的两种方法都会为您提供枚举名称。


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


但请记住,第二种技术假设您正在使用整数并且您的索引是基于1(不是基于0)。相比之下,GetNames函数也相当繁重,每次调用它时都会产生一个完整的数组。
正如您在第一种技术中所看到的,.ToString()实际上是隐式调用的。
当然,答案中已经提到了这两点,我只是想澄清它们之间的差异。

其它参考23


旧帖但是......


对此的答案实际上可能非常简单。使用Enum.ToString()函数[95]


这个函数有6个重载,你可以使用Enum.Tostring(F)或Enum.ToString()来返回字符串值。无需为其他任何事情烦恼。这是一个有效的演示[96]


请注意,此解决方案可能不适用于所有编译器(此演示不能按预期工作),但至少它适用于最新的编译器。[97]

其它参考24


基于MSDN:http://msdn.microsoft.com/en-us/library/cc138362.aspx [98]


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


str将是字段的名称

其它参考25


好了,在阅读了上述所有内容后,我觉得这些人已经过度复杂了将枚举数转换为字符串的问题。
我喜欢在枚举字段上使用属性的想法,但我认为属性主要用于元数据,但在您的情况下,我认为您需要的只是某种本地化。


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


现在,如果我们尝试调用上面的方法,我们可以这样调用它


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


您只需创建一个包含所有枚举器值和相应字符串的资源文件即可


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


实际上非常好的是,如果您需要将应用程序本地化,它将非常有用,因为您只需要使用新语言创建另一个资源文件!和Voe-la!

其它参考26


当我处于这样的情况时,我提出下面的解决方案。


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


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

    }
}


并使用双向字典:
基于此(https://stackoverflow.com/a/255638/986160),假设密钥将与字典中的单个值相关联,类似于(https://stackoverflow.com/a/255630/986160)但更优雅一点。这个字典也是可枚举的,你可以从int到字符串来回转换。此外,除了此类之外,您不必在代码库中包含任何字符串。


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

其它参考27


这里有很多很棒的答案,但在我的情况下并没有解决我想要的字符串枚举,这是:



  1. 可用于switch语句,例如switch(myEnum)

  2. 可用于功能参数,例如foo(myEnum类型)

  3. 可以参考,例如myEnum.FirstElement

  4. 我可以使用字符串,例如foo(FirstElement)== foo(myEnum.FirstElement)



1,2& 4实际上可以用字符串的C#Typedef来解决(因为字符串可以在c#中切换)


3可以通过静态const字符串来解决。因此,如果您有相同的需求,这是最简单的方法:


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

}


这允许例如:


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





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

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }


可以使用字符串或类型调用CreateType。 然而缺点是任何字符串都是自动有效的枚举,这可能会被修改但是它需要某种初始化函数......或者可能使它们显式内置?


现在,如果一个int值对你很重要(也许是为了比较速度),你可以使用来自JakubŠturc的一些想法很棒的答案并做一些位疯狂的事情,这是我的刺伤它:


    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

}


但当然类型bob=4;除非你先把它们初始化,否则会失败,这将毫无意义......


但理论上TypeA == TypeB会更快......

其它参考28


使用对象Enum.Parse(System.Type enumType,string value,bool ignoreCase); 从http://blogs.msdn.com/b/tims/archive/2004/04/02/获取106310.aspx [101]

其它参考29


我的回答是,@ user29964的答案(这是迄今为止最简单和最接近Enum)的答案


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


这将回来
六,排名