我有以下列举:
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);
好的,现在所有这些工作就像一个魅力,但我发现它有很多工作。我想知道有没有更好的解决办法。
我还尝试了一些字典和静态属性,但这也不是更好。
我的变体
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)。
不幸的是,在枚举上获取属性的反射非常慢:
看这个问题:有人知道一种快速获取枚举值的自定义属性的方法吗?
. 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"
这里有很多很棒的答案,但在我的情况下,并没有解决我想要的“字符串enum”,这是:
可用在switch语句中,例如switch(myEnum)
可以在函数参数中使用,例如foo(myEnum类型)
可以引用,例如myEnum。FirstElement
我可以使用字符串,例如foo("FirstElement") == foo(myenumer .FirstElement)
1、2和4实际上可以用一个字符串的c#类型定义来解决(因为字符串在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
}
and
public TypeObject CreateType(Types type)
{
switch (type)
{
case Types.ImageType:
//
break;
case Types.DataType:
//
break;
}
}
CreateType可以用字符串或类型调用。然而,缺点是任何字符串都是自动有效的enum,这可以被修改,但它将需要某种init函数…或者可能使它们显式转换内部?
现在,如果一个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
}
但是当然"Types bob = 4;"是没有意义的,除非你先对它们进行初始化,这就有点失败了……
但理论上a型== b型会更快…
我发现的Enums国际化或从各自的资源文件获取Enums文本的方法是通过继承DescriptionAttribute类创建一个属性类
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;
}
}
创建另一个Static类,为GetString和GetString提供扩展方法。
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();
}
}
在Enum的元素上,你可以这样写:
public enum Priority
{
[EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh, 1)]
High,
[EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine, 2)]
Routine
}
Where Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh &
resources . resourcename . advicecreateadviceexternaprioritymemberroutine是资源文件中的常量,或者你可以说字符串,其值可以在不同的文化中可用。
如果你在MVC架构中实现你的web应用程序,那么创建一个属性
private IList result;
public IList Result
{
get
{
result = typeof(Priority).GetStrings();
return result;
}
}
在你的.cshtml文件中,你可以像这样将枚举绑定到你的下拉列表:
@Html.DropDownListFor(model => Model.vwClinicalInfo.Priority, new SelectList(Model.Result))
谢谢
Ratnesh