关于C#:枚举的字符串表示形式

String representation of an Enum

我有以下列举:

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

然而,问题是,当我请求authenticationMethod.forms而不是ID 1时,我需要单词"forms"。

我已找到此问题的以下解决方案(链接):

首先,我需要创建一个名为"stringvalue"的自定义属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StringValue : System.Attribute
{
    private readonly string _value;

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

    public string Value
    {
        get { return _value; }
    }

}

然后我可以将此属性添加到枚举器中:

1
2
3
4
5
6
7
8
9
public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

当然,我需要一些东西来检索这个字符串值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
    }
}

很好,现在我有了获取枚举器字符串值的工具。然后我可以这样使用它:

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

好吧,现在所有这些工作都很有魅力,但我发现它需要很多工作。我想知道是否有更好的解决办法。

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


尝试键入安全枚举模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
    }

}

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

  • 使用映射添加静态字段

    1
    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    • 注意,"枚举成员"字段的初始化在调用实例构造函数时不会引发NullReferenceException,请确保将字典字段放在类中的"枚举成员"字段之前。这是因为静态字段初始化器是按声明顺序调用的,在静态构造函数之前,创建了一种奇怪的、必要的但令人困惑的情况,即可以在初始化所有静态字段之前和调用静态构造函数之前调用实例构造函数。
  • 在实例构造函数中填充此映射

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

    1
    2
    3
    4
    5
    6
    7
    8
    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是定义的枚举)

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

枚举类上还有许多其他静态方法值得研究…


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

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

文件如下:

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

…如果您在pascal情况下命名枚举(如thisismyNumValue=1等),则可以使用非常简单的regex打印友好的表单:

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

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

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

输出:

Convert My Crazy Pascal Case Sentence To Friendly Case

这节省了在房屋周围运行创建自定义属性并将它们附加到枚举中,或者使用查找表将枚举值与友好的字符串结合在一起(最好是它的自我管理),并且可以用于任何更加可重用的pascal case字符串。当然,它不允许您使用与解决方案提供的枚举不同的友好名称。

不过,对于更复杂的场景,我确实喜欢您的原始解决方案。您可以进一步研究解决方案,使GetStringValue成为枚举的扩展方法,然后您就不需要像StringEnum.GetStringValue那样引用它了…

1
2
3
4
5
6
7
8
9
10
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;
}

然后可以直接从枚举实例轻松访问它:

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


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

看到这个问题:有人知道一种快速的方法来获取枚举值的自定义属性吗?

.ToString()在枚举方面也相当慢。

但是,您可以编写枚举的扩展方法:

1
2
3
4
5
6
7
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",这是获取枚举名称的最快方法。

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

1
nameof(AuthenticationMethod.FORMS) =="FORMS"

但是…

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


我使用扩展方法:

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
8
9
public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON")]
    SINGLESIGNON = 3
}

当你打电话

你会得到"FORMS"


只需使用ToString()方法

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

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

1
any.Tomato.ToString();


我使用system.componentModel命名空间中的description属性。只需修饰枚举,然后使用此代码检索它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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();

        }

举个例子:

1
2
3
4
5
6
7
public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

此代码很好地满足了不需要"友好名称"的枚举,并且只返回枚举的.toString()。


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

1
2
3
4
5
public enum MyStatus
{
    Active = 1,
    Archived = 2
}

要获取关于just use的字符串:

1
MyStatus.Active.ToString("f");

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

该值将为"活动"或"存档"。

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


我真的喜欢杰克?Turc的答案,但它的缺点是不能将它与switch case语句一起使用。下面是一个稍微修改过的答案版本,可以与switch语句一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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");
}

所以你得到了雅库布的所有好处?Turc的答案,另外,我们可以将其与如下switch语句一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;      
}


在您的问题中,您从未说过您实际上需要枚举的任何位置的数值。

如果您不需要并且只需要一个string类型的枚举(它不是整型的,因此不能是枚举的基),下面是一种方法:

1
2
3
4
5
6
    static class AuthenticationMethod
    {
        public static readonly string
            FORMS ="Forms",
            WINDOWSAUTHENTICATION ="WindowsAuthentication";
    }

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

1
if (bla == AuthenticationMethod.FORMS)

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


我结合使用上面的几个建议,并结合一些缓存。现在,我从网上某个地方找到的代码中得到了这个想法,但是我不记得从哪里得到的或者找到的。因此,如果有人发现类似的东西,请评论其属性。

不管怎样,这种用法涉及类型转换器,因此如果您绑定到UI,它就"正常工作"。通过从类型转换器初始化为静态方法,可以使用Jakub的模式进行扩展,以便快速查找代码。

基本用法如下

1
2
3
4
5
6
7
8
9
10
[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
}

自定义枚举类型转换器的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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);
    }
}

}


作为你们大多数人,我真的很喜欢杰克选择的答案?但是我也很讨厌复制粘贴代码,并且尽可能少地做。

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

这种方法的主要问题是基于这样一个事实:尽管枚举值是类型安全的实例,但是交互是与枚举类类型的静态实现进行的。所以在仿制药的帮助下,我想我终于得到了正确的组合。希望有人能像我一样发现这一点。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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); }
}

下面是基本类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
}


我如何将此作为扩展方法来解决:

1
2
3
4
5
6
7
8
9
10
11
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();
}

枚举:

1
2
3
4
5
6
7
8
public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

用法(其中o.orderType是与枚举同名的属性):

1
o.OrderType.GetDescription()

它给我一个字符串"new card"或"reload",而不是实际的枚举值new card并重新填充。


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

我使用静态方法和swith语句返回我想要的。在我存储tinyint的数据库中,我的代码只使用实际的枚举,因此字符串是用于UI需求的。经过多次测试,这导致了最佳的性能和对输出的大部分控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
     }
}

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


如果您来这里希望实现一个简单的"枚举",但其值是字符串而不是整数,那么这里是最简单的解决方案:

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

实施:

1
var someStringVariable = MetricValueList.Brand;


我想在下面引用的帖子上发表评论,但不能,因为我没有足够的代表-所以请不要拒绝投票。代码包含一个错误,我想向试图使用此解决方案的个人指出这一点:

1
2
3
4
5
6
7
8
9
[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
}

应该是

1
2
3
4
5
6
7
8
9
10
[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
}

闪耀!


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

  • 我的枚举值的名称是否足够友好,或者我是否需要提供更友好的名称?
  • 我需要往返吗?也就是说,我需要获取文本值并将其解析为枚举值吗?
  • 在我的项目中,这是我需要为许多枚举做的事情,还是只需要一个?
  • 我将呈现哪些类型的UI元素—特别是,我将绑定到UI,还是使用属性表?
  • 这需要本地化吗?

最简单的方法是使用Enum.GetValue(并使用Enum.Parse支持往返)。正如SteveMitcham所建议的,构建一个TypeConverter来支持UI绑定通常也是值得的。(使用属性表时,不必构建TypeConverter,这是属性表的一个优点。虽然上帝知道他们有自己的问题。)

一般来说,如果上述问题的答案表明这行不通,我的下一步就是创建和填充一个静态的Dictionary,或者可能是Dictionary>。我倾向于跳过中间用属性来修饰代码的步骤,因为通常接下来需要在部署之后更改友好的值(通常,但不总是,因为本地化)。


我的变体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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;
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)。


选项1:

1
2
3
4
5
6
7
8
9
10
11
12
13
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";}
}

然后

1
2
3
4
5
6
7
object auth = new SsoAuth(); //or whatever

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

DoSomethingWithTheAuth(auth.ToString());

选项2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的类型安全枚举模式是我在这里看到的最佳选项。

看看它:

  • 它有一个私有的构造函数,因此只有类本身才能定义允许的值。
  • 它是一个密封类,因此不能通过继承来修改值。
  • 它是类型安全的,允许您的方法只需要该类型。
  • 访问这些值不会影响反射性能。
  • 最后,可以修改它,将两个以上的字段关联在一起,例如名称、描述和数值。

对于我来说,实用主义方法是类内的类,示例:

1
2
3
4
5
6
7
8
9
10
11
12
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";
...
    }

下面是另一种完成字符串与枚举关联任务的方法:

1
2
3
4
5
6
7
8
9
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];
    }
}

此方法的调用方式如下:

1
2
3
4
5
public FormMain() {
    DATABASE dbEnum;

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

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

您可以选择在DATABASE结构上使用new运算符。不使用它意味着直到第一个GetString()调用后,字符串List才被分配。


这里有很多很好的答案,但在我的例子中,没有解决我想要的"字符串枚举",即:

  • 在switch语句中可用,例如switch(myenum)
  • 可用于函数参数,例如foo(myenum类型)
  • 可以引用,例如myenum.firstelement
  • 我可以使用字符串,例如foo("firstelement")==foo(myenum.firstelement)
  • 1,2&4实际上可以用字符串的c typedef来解决(因为字符串可以在c中切换)

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    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

    }

    例如,这允许:

    1
    2
    3
    4
        public TypeArgs(Types SelectedType)
        {
            Types SelectedType = SelectedType
        }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public TypeObject CreateType(Types type)
        {
            switch (type)
            {

                case Types.ImageType:
                  //
                    break;

                case Types.DataType:
                 //
                    break;

            }
        }

    其中,可以使用字符串或类型调用CreateType。但是,缺点是任何字符串都是自动有效的枚举,可以修改它,但是它将需要某种类型的init函数…或者可能使它们显式转换为内部的?

    现在,如果一个int值对您很重要(可能是为了比较速度),您可以使用Jakub的一些想法吗?你的回答太好了,做点疯狂的事,这是我的一个尝试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
        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

    }

    但当然,"types bob=4;"将毫无意义,除非您先初始化它们,这将有点破坏要点…

    但理论上,typeA==typeB会更快…


    如果我对您的理解正确,您可以简单地使用.toString()从值中检索枚举的名称(假设它已经转换为枚举);如果有naked int(比如从数据库或其他地方),可以首先将其强制转换为枚举。下面的两个方法都将获得枚举名称。

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

    不过请记住,第二种技术假定您使用的是int,并且您的索引是基于1的(而不是基于0的)。相比之下,getname函数也很重,每次调用它时都会生成一个完整的数组。正如您在第一个技术中看到的那样,.toString()实际上是隐式调用的。当然,答案中已经提到了这两个问题,我只是想澄清它们之间的区别。


    老职位但是…

    答案可能非常简单。使用Enum.ToString()函数

    此函数有6个重载,可以使用Enum.ToString("f")或Enum.ToString()返回字符串值。不必为别的事费心。这是一个有效的演示

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


    当我遇到这样的情况时,我会提出下面的解决方案。

    作为一个消费阶层,你可以

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    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到strings来回查找。另外,除了这个类之外,代码库中不需要任何字符串。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    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();
            }
        }
    }

    好吧,在阅读了以上所有内容之后,我觉得这些人把枚举器转换成字符串的问题过于复杂了。我喜欢在枚举字段上拥有属性的想法,但我认为属性主要用于元数据,但在您的例子中,我认为您所需要的只是某种本地化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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;
        }
    }

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

    1
    2
    3
    4
    5
    public void Foo()
    {
      var col = Color.Red;
      Console.WriteLine (EnumUtils.GetEnumResourceString (col));
    }

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

    1
    2
    3
    4
    Resource Name          Resource Value
    Color_Red              My String Color in Red
    Color_Blue             Blueeey
    Color_Green            Hulk Color

    这实际上是非常好的一点,如果您需要将应用程序本地化,这将非常有帮助,因为您所需要做的只是用新语言创建另一个资源文件!还有Voe la!


    对于较大的字符串枚举集,列出的示例可能会变得令人厌烦。如果需要状态代码列表或其他基于字符串的枚举列表,则使用属性系统很烦人,配置带有自身实例的静态类也很烦人。对于我自己的解决方案,我使用了t4模板,以使使用字符串支持的枚举更容易。结果与httpmethod类的工作方式类似。

    您可以这样使用它:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        string statusCode = ResponseStatusCode.SUCCESS; // Automatically converts to string when needed
        ResponseStatusCode codeByValueOf = ResponseStatusCode.ValueOf(statusCode); // Returns null if not found

        // Implements TypeConverter so you can use it with string conversion methods.
        var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(ResponseStatusCode));
        ResponseStatusCode code = (ResponseStatusCode) converter.ConvertFromInvariantString(statusCode);

        // You can get a full list of the values
        bool canIterateOverValues = ResponseStatusCode.Values.Any();

        // Comparisons are by value of the"Name" property. Not by memory pointer location.
        bool implementsByValueEqualsEqualsOperator ="SUCCESS" == ResponseStatusCode.SUCCESS;

    从一个enum.tt文件开始。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <#@ include file="StringEnum.ttinclude" #>


    <#+
    public static class Configuration
    {
        public static readonly string Namespace ="YourName.Space";
        public static readonly string EnumName ="ResponseStatusCode";
        public static readonly bool IncludeComments = true;

        public static readonly object Nodes = new
        {
            SUCCESS ="The response was successful.",
            NON_SUCCESS ="The request was not successful.",
            RESOURCE_IS_DISCONTINUED ="The resource requested has been discontinued and can no longer be accessed."
        };
    }
    #>

    然后,添加StringEnum.ttinclude文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Reflection" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ output extension=".cs" #>
    <#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>

    //------------------------------------------------------------------------------
    //
    //     This code was generated by a tool.
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;

    namespace <#= Configuration.Namespace #>
    {
        /// <summary>
        /// TypeConverter implementations allow you to use features like string.ToNullable(T).
        /// </summary>
        public class <#= Configuration.EnumName #>TypeConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                var casted = value as string;

                if (casted != null)
                {
                    var result = <#= Configuration.EnumName #>.ValueOf(casted);
                    if (result != null)
                    {
                        return result;
                    }
                }

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

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                var casted = value as <#= Configuration.EnumName #>;
                if (casted != null && destinationType == typeof(string))
                {
                    return casted.ToString();
                }

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

        [TypeConverter(typeof(<#= Configuration.EnumName #>TypeConverter))]
        public class <#= Configuration.EnumName #> : IEquatable<<#= Configuration.EnumName #>>
        {
    //---------------------------------------------------------------------------------------------------
    // V A L U E S _ L I S T
    //---------------------------------------------------------------------------------------------------
    <# Write(Helpers.PrintEnumProperties(Configuration.Nodes)); #>

            private static List<<#= Configuration.EnumName #>> _list { get; set; } = null;
            public static List<<#= Configuration.EnumName #>> ToList()
            {
                if (_list == null)
                {
                    _list = typeof(<#= Configuration.EnumName #>).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(<#= Configuration.EnumName #>))
                        .Select(x => x.GetValue(null)).OfType<<#= Configuration.EnumName #>>().ToList();
                }

                return _list;
            }

            public static List<<#= Configuration.EnumName #>> Values()
            {
                return ToList();
            }

            /// <summary>
            /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static <#= Configuration.EnumName #> ValueOf(string key)
            {
                return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
            }


    //---------------------------------------------------------------------------------------------------
    // I N S T A N C E _ D E F I N I T I O N
    //---------------------------------------------------------------------------------------------------      
            public string Name { get; private set; }
            public string Description { get; private set; }
            public override string ToString() { return this.Name; }

            /// <summary>
            /// Implcitly converts to string.
            /// </summary>
            /// <param name="d"></param>
            public static implicit operator string(<#= Configuration.EnumName #> d)
            {
                return d.ToString();
            }

            /// <summary>
            /// Compares based on the == method. Handles nulls gracefully.
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public static bool operator !=(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
            {
                return !(a == b);
            }

            /// <summary>
            /// Compares based on the .Equals method. Handles nulls gracefully.
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public static bool operator ==(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
            {
                return a?.ToString() == b?.ToString();
            }

            /// <summary>
            /// Compares based on the .ToString() method
            /// </summary>
            /// <param name="o"></param>
            /// <returns></returns>
            public override bool Equals(object o)
            {
                return this.ToString() == o?.ToString();
            }

            /// <summary>
            /// Compares based on the .ToString() method
            /// </summary>
            /// <param name="other"></param>
            /// <returns></returns>
            public bool Equals(<#= Configuration.EnumName #> other)
            {
                return this.ToString() == other?.ToString();
            }

            /// <summary>
            /// Compares based on the .Name property
            /// </summary>
            /// <returns></returns>
            public override int GetHashCode()
            {
                return this.Name.GetHashCode();
            }
        }
    }

    <#+

    public static class Helpers
    {
            public static string PrintEnumProperties(object nodes)
            {
                string o ="";
                Type nodesTp = Configuration.Nodes.GetType();
                PropertyInfo[] props = nodesTp.GetProperties().OrderBy(p => p.Name).ToArray();

                for(int i = 0; i < props.Length; i++)
                {
                    var prop = props[i];
                    if (Configuration.IncludeComments)
                    {
                        o +="



    "
    ;
                        o +="

            ///<summary>"
    ;
                        o +="

            ///"
    +Helpers.PrintPropertyValue(prop, Configuration.Nodes);
                        o +="

            ///</summary>"
    ;
                    }

                    o +="

            public static readonly"
    +Configuration.EnumName+""+prop.Name+" = new"+Configuration.EnumName+"(){ Name = ""+prop.Name+"", Description ="+Helpers.PrintPropertyValue(prop, Configuration.Nodes)+"};";
                }

                o +="



    "
    ;

                return o;
            }

            private static Dictionary<string, string> GetValuesMap()
            {
                Type nodesTp = Configuration.Nodes.GetType();
                PropertyInfo[] props= nodesTp.GetProperties();
                var dic = new Dictionary<string,string>();
                for(int i = 0; i < props.Length; i++)
                {
                    var prop = nodesTp.GetProperties()[i];
                    dic[prop.Name] = prop.GetValue(Configuration.Nodes).ToString();
                }
                return dic;
            }

            public static string PrintMasterValuesMap(object nodes)
            {
                Type nodesTp = Configuration.Nodes.GetType();
                PropertyInfo[] props= nodesTp.GetProperties();
                string o ="        private static readonly Dictionary<string, string> ValuesMap = new Dictionary<string, string>()

            {"
    ;
                for(int i = 0; i < props.Length; i++)
                {
                    var prop = nodesTp.GetProperties()[i];
                    o +="

                { "
    "+prop.Name+"","+(Helpers.PrintPropertyValue(prop,Configuration.Nodes)+" },");
                }
                o += ("

            };

    "
    );

                return o;
            }


            public static string PrintPropertyValue(PropertyInfo prop, object objInstance)
            {
                switch(prop.PropertyType.ToString()){
                    case"System.Double":
                        return prop.GetValue(objInstance).ToString()+"D";
                    case"System.Float":
                        return prop.GetValue(objInstance).ToString()+"F";
                    case"System.Decimal":
                        return prop.GetValue(objInstance).ToString()+"M";
                    case"System.Long":
                        return prop.GetValue(objInstance).ToString()+"L";
                    case"System.Boolean":
                    case"System.Int16":
                    case"System.Int32":
                        return prop.GetValue(objInstance).ToString().ToLowerInvariant();
                    case"System.String":
                        return"""+prop.GetValue(objInstance)+""";
                }

                return prop.GetValue(objInstance).ToString();
            }

            public static string _ (int numSpaces)
            {
                string o ="";
                for(int i = 0; i < numSpaces; i++){
                    o +="";
                }

                return o;
            }
    }
    #>

    最后,重新编译enum.tt文件,输出如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    //------------------------------------------------------------------------------
    //
    //     This code was generated by a tool.
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------

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

    namespace YourName.Space
    {
        public class ResponseStatusCode
        {
    //---------------------------------------------------------------------------------------------------
    // V A L U E S _ L I S T
    //---------------------------------------------------------------------------------------------------



            ///<summary>
            ///"The response was successful."
            ///</summary>
            public static readonly ResponseStatusCode SUCCESS = new ResponseStatusCode(){ Name ="SUCCESS", Description ="The response was successful."};


            ///<summary>
            ///"The request was not successful."
            ///</summary>
            public static readonly ResponseStatusCode NON_SUCCESS = new ResponseStatusCode(){ Name ="NON_SUCCESS", Description ="The request was not successful."};


            ///<summary>
            ///"The resource requested has been discontinued and can no longer be accessed."
            ///</summary>
            public static readonly ResponseStatusCode RESOURCE_IS_DISCONTINUED = new ResponseStatusCode(){ Name ="RESOURCE_IS_DISCONTINUED", Description ="The resource requested has been discontinued and can no longer be accessed."};


            private static List<ResponseStatusCode> _list { get; set; } = null;
            public static List<ResponseStatusCode> ToList()
            {
                if (_list == null)
                {
                    _list = typeof(ResponseStatusCode).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(ResponseStatusCode))
                        .Select(x => x.GetValue(null)).OfType<ResponseStatusCode>().ToList();
                }

                return _list;
            }

            public static List<ResponseStatusCode> Values()
            {
                return ToList();
            }

            /// <summary>
            /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static ResponseStatusCode ValueOf(string key)
            {
                return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
            }


    //---------------------------------------------------------------------------------------------------
    // I N S T A N C E _ D E F I N I T I O N
    //---------------------------------------------------------------------------------------------------      
            public string Name { get; set; }
            public string Description { get; set; }
            public override string ToString() { return this.Name; }

            /// <summary>
            /// Implcitly converts to string.
            /// </summary>
            /// <param name="d"></param>
            public static implicit operator string(ResponseStatusCode d)
            {
                return d.ToString();
            }

            /// <summary>
            /// Compares based on the == method. Handles nulls gracefully.
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public static bool operator !=(ResponseStatusCode a, ResponseStatusCode b)
            {
                return !(a == b);
            }

            /// <summary>
            /// Compares based on the .Equals method. Handles nulls gracefully.
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public static bool operator ==(ResponseStatusCode a, ResponseStatusCode b)
            {
                return a?.ToString() == b?.ToString();
            }

            /// <summary>
            /// Compares based on the .ToString() method
            /// </summary>
            /// <param name="o"></param>
            /// <returns></returns>
            public override bool Equals(object o)
            {
                return this.ToString() == o?.ToString();
            }

            /// <summary>
            /// Compares based on the .Name property
            /// </summary>
            /// <returns></returns>
            public override int GetHashCode()
            {
                return this.Name.GetHashCode();
            }
        }
    }

    基于msdn:http://msdn.microsoft.com/en-us/library/cc138362.aspx

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

    str将是字段的名称


    我为枚举国际化或从各自的资源文件中获取枚举文本找到的方法是通过继承DescriptionAttribute类来创建一个属性类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class EnumResourceAttribute : DescriptionAttribute
    {

        public Type ResourceType { get; private set; }
        public string ResourceName { get; private set; }
        public int SortOrder { get; private set; }
        public EnumResourceAttribute(Type ResourceType,
                             string ResourceName,
                             int SortOrder)
        {

            this.ResourceType = ResourceType;
            this.ResourceName = ResourceName;
            this.SortOrder = SortOrder;
        }
    }

    创建另一个静态类,该类将为GetString和GetStrings提供扩展方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    public static class EnumHelper
    {
        public static string GetString(this Enum value)
        {
            EnumResourceAttribute ea =
           (EnumResourceAttribute)value.GetType().GetField(value.ToString())
            .GetCustomAttributes(typeof(EnumResourceAttribute), false)
             .FirstOrDefault();
            if (ea != null)
            {
                PropertyInfo pi = ea.ResourceType
                 .GetProperty(CommonConstants.ResourceManager);
                if (pi != null)
                {
                    ResourceManager rm = (ResourceManager)pi
                    .GetValue(null, null);
                    return rm.GetString(ea.ResourceName);
                }

            }
            return string.Empty;
        }


        public static IList GetStrings(this Type enumType)
        {
            List<string> stringList = new List<string>();
            FieldInfo[] fiArray = enumType.GetFields();
            foreach (FieldInfo fi in fiArray)
            {
                EnumResourceAttribute ea =
                    (EnumResourceAttribute)fi
                         .GetCustomAttributes(typeof(EnumResourceAttribute), false)
                         .FirstOrDefault();
                if (ea != null)
                {
                    PropertyInfo pi = ea.ResourceType
                                        .GetProperty(CommonConstants.ResourceManager);
                    if (pi != null)
                    {
                        ResourceManager rm = (ResourceManager)pi
                                              .GetValue(null, null);
                        stringList.Add(rm.GetString(ea.ResourceName));
                    }
                }
            }
            return stringList.ToList();
        }
    }

    在枚举的元素上,可以编写:

    1
    2
    3
    4
    5
    6
    7
    public enum Priority
    {
         [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh, 1)]
        High,
         [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine, 2)]
        Routine
    }

    其中resources.resourceNames.adviceCreateAdviceExternalPriorityMemberHigh&;resources.resourceNames.adviceCreateAdviceExternalPriorityMemberRoutine是资源文件中的常量,也可以说其值可以在不同的区域性中使用。

    如果要在MVC体系结构中实现Web应用程序,请创建一个属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private IList result;
    public IList Result
    {
        get
        {
            result = typeof(Priority).GetStrings();
            return result;
        }
    }

    在.cshtml文件中,您可以将枚举绑定到DropDownList,如下所示:

    1
    @Html.DropDownListFor(model => Model.vwClinicalInfo.Priority, new SelectList(Model.Result))

    谢谢拉特涅什


    使用object enum.parse(system.type enum type,string value,bool ignorecase);从http://blogs.msdn.com/b/tims/archive/2004/04/02/106310.aspx获取


    我和哈维在一起,但不要用警察。我可以混合和匹配字符串,int,随便什么。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class xlsLayout
    {
        public int xlHeaderRow = 1;
        public int xlFirstDataRow = 2;
        public int xlSkipLinesBetweenFiles = 1; //so 0 would mean don't skip
        public string xlFileColumn ="A";
        public string xlFieldColumn ="B";
        public string xlFreindlyNameColumn ="C";
        public string xlHelpTextColumn ="D";
    }

    后来…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public partial class Form1 : Form
    {
        xlsLayout xlLayout = new xlsLayout();

        xl.SetCell(xlLayout.xlFileColumn, xlLayout.xlHeaderRow,"File Name");
        xl.SetCell(xlLayout.xlFieldColumn, xlLayout.xlHeaderRow,"Code field name");
        xl.SetCell(xlLayout.xlFreindlyNameColumn, xlLayout.xlHeaderRow,"Freindly name");
        xl.SetCell(xlLayout.xlHelpTextColumn, xlLayout.xlHeaderRow,"Inline Help Text");
    }


    1
    2
    3
    Enum.GetName(typeof(MyEnum), (int)MyEnum.FORMS)
    Enum.GetName(typeof(MyEnum), (int)MyEnum.WINDOWSAUTHENTICATION)
    Enum.GetName(typeof(MyEnum), (int)MyEnum.SINGLESIGNON)

    输出是:

    "形式"

    "Windows身份验证"

    "单音素"


    对于@user29964的答案(这是迄今为止最简单和最接近枚举的答案),我的答案是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     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);

            }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [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
     }

    例子

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

    这个会回来的"vi,排名"


    我非常清楚这个问题已经被回答了,并且OP已经对被接受的答案感到满意了。但我发现大多数答案,包括被接受的答案,都有点复杂。

    我有一个项目,给了我这样的情况,我能够做到这一点。

    首先,必须考虑枚举名称的大小写:

    1
    2
    3
    4
    5
    6
    public enum AuthenticationMethod
    {
        Forms = 1,
        WindowsAuthentication = 2,
        SingleSignOn = 3
    }

    然后,进行扩展:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    using System.Text.RegularExpression;

    public static class AnExtension
    {
        public static string Name(this Enum value)
        {
            string strVal = value.ToString();
            try
            {
                return Regex.Replace(strVal,"([a-z])([A-Z])","$1 $2");
            }
            catch
            {
            }
            return strVal;
        }
    }

    通过这种方式,您可以将每个枚举名称转换为字符串表示形式,每个单词之间用空格分隔。前任:

    1
    2
    AuthenticationMethod am = AuthenticationMethod.WindowsAuthentication;
    MessageBox.Show(am.Name());