CSharp - c#字符串枚举

  显示原文与译文双语对照的内容

我有以下枚举:


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

然而问题在于我需要"窗体"当我问这个词 AuthenticationMethod.FORMS 1而不是id。

我已经为这个问题找到了以下解决方案( 链接 ):

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


public class StringValue : System.Attribute
{
 private 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 样式。


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

}


更新 Explicit显式( 或者隐式) 类型转换可以由

  • 使用映射添加静态字段

    
    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    
    • n.b 。为了使"枚举成员"字段的初始化在调用实例构造函数时不引发 NullReferenceException,请确保在类的"枚举成员"字段之前放置字典字段。 这是因为静态字段initialisers是以声明顺序调用的,在静态构造函数之前,创建了一个奇怪且必要的情况,该场景在初始化所有静态字段之前,并在调用静态构造函数之前调用。
  • 在实例构造函数中填充这里映射

    
    instance[name] = this;
    
    
  • 并添加 user-defined类型转换运算符

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

使用方法


Enum.GetName(Type MyEnumType, object enumvariable) 

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


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

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

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


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

文档在这里:

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

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


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

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


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

输出:

将我的疯狂Pascal案例句转换为友好案例

节省运行一圈房子创建自定义属性和附加到枚举或使用查找表嫁给一个枚举值与一个友好的字符串,最重要的是它是自我管理和可用于任何帕斯卡情况下更可重用的字符串。 当然,它不允许你拥有一个与你的解决方案所提供的枚举不同的的友好名称。

虽然更复杂的场景,我还是喜欢你原来的解决方案。 你可以更进一步,使你的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());

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

查看这个问题:http://stackoverflow.com/questions/17772

.ToString()的枚举速度太慢。

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


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

这不是很好,但将很快,不需要属性或者字段名称的反射。

我使用了一个扩展方法:


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"

我使用来自 System.ComponentModel 命名空间的描述属性。 只需修饰该枚举,然后使用这里代码检索它:


public static string GetDescription<T>(this object enumerationValue)
 where T : struct
 {
 Type type = enumerationValue.GetType();
 if (!type.IsEnum)
 {
 throw new ArgumentException("EnumerationValue must be of Enum type","enumerationValue");
 }

//Tries to find a DescriptionAttribute for a potential friendly name
//for the enum
 MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
 if (memberInfo!= null && memberInfo.Length> 0)
 {
 object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

 if (attrs!= null && attrs.Length> 0)
 {
//Pull out the description value
 return ((DescriptionAttribute)attrs[0]).Description;
 }
 }
//If we have no description attribute, just return the ToString of the enum
 return enumerationValue.ToString();

 }

举例来说,


public enum Cycle : int
{ 
 [Description("Daily Cycle")]
 Daily = 1,
 Weekly,
 Monthly
}

这段代码很好地迎合了你不需要"好记的名称"的枚举,并且只返回枚举的. ToString() 。

只使用 ToString() 方法


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

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


any.Tomato.ToString();

这是稍微修改版本的他的回答,可以使用 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");
}


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

我使用了上面几个建议的组合,结合一些缓存。 现在,我从一些代码中找到了我在网络上找到的想法,但我不能记住我在哪里找到它或者找到它。 所以如果有人发现类似的东西,请用属性评论。

无论如何,使用的是类型转换器,所以如果你要绑定到用户界面,它'只是工作'。 通过将类型转换器从类型转换器初始化为静态方法,可以扩展Jakub的模式以进行快速代码查找。

基本用法如下所示


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

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


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

%7D

我同意 Keith ,但我不能投票给( 还还还) 。

我使用静态方法和交换语句来准确返回我想要的。 在数据库中存储tinyint和我的代码只使用实际的枚举,所以字符串是用于用户界面需求的。 经过大量测试,这导致了最好的性能和对输出的控制。


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

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

但是,通过一些帐户,这导致了一个可能的维护噩梦和一些 代码异味 。 我试图密切关注长的和大量的枚举,或者那些频繁变化的枚举。 否则,这对我来说是一个很好的解决方案。

...