我有以下列举:

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

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

对于这个问题,我找到了以下解决方案(链接):

首先,我需要创建一个自定义属性“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);

好的,现在所有这些工作就像一个魅力,但我发现它有很多工作。我想知道有没有更好的解决办法。

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


当前回答

我同意基斯的意见,但我还不能投票。

我使用一个静态方法和swith语句来返回我想要的结果。在数据库中,我存储tinyint和我的代码只使用实际的enum,所以字符串是为UI需求。经过大量的测试,这导致了最好的性能和最好的控制输出。

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

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

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

其他回答

试试type-safe-enum模式。

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

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

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

    public override String ToString(){
        return name;
    }

}

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

adding static field with mapping private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>(); n.b. In order that the initialisation of the the "enum member" fields doesn't throw a NullReferenceException when calling the instance constructor, be sure to put the Dictionary field before the "enum member" fields in your class. This is because static field initialisers are called in declaration order, and before the static constructor, creating the weird and necessary but confusing situation that the instance constructor can be called before all static fields have been initialised, and before the static constructor is called. filling this mapping in instance constructor instance[name] = this; and adding user-defined type conversion operator public static explicit operator AuthenticationMethod(string str) { AuthenticationMethod result; if (instance.TryGetValue(str, out result)) return result; else throw new InvalidCastException(); }

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

我有一个项目给了我这样的情况,我能够以这种方式实现它。

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

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

然后,有这个扩展:

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

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

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

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

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

. tostring()在枚举上也相当慢。

你可以为枚举写扩展方法:

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

这不是很好,但是很快,而且不需要对属性或字段名进行反射。


c# 6更新

如果你可以使用c# 6,那么操作符的新名称适用于枚举,因此nameof(myenume .WINDOWSAUTHENTICATION)将在编译时转换为“WINDOWSAUTHENTICATION”,使其成为获取枚举名称的最快方式。

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

nameof(AuthenticationMethod.FORMS) == "FORMS"

但是…

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

我想把这篇文章作为下面引用的帖子的评论,但不能,因为我没有足够的代表。代码包含一个错误,我想向试图使用这个解决方案的个人指出这一点:

[TypeConverter typeof (CustomEnumTypeConverter (typeof (MyEnum))) public enum MyEnum { //自定义类型转换器将使用description属性 [描述(“自定义描述”)] ValueWithCustomDescription, //这将完全暴露。 确切的 }

应该是

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

我真的很喜欢Jakub Šturc的答案,但它的缺点是不能与开关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;      
}