我有以下枚举:
public enum AuthenticationMethod
{
FORMS = 1,
WINDOWSAUTHENTICATION = 2,
SINGLESIGNON = 3
}
Run Code Online (Sandbox Code Playgroud)
然而问题是,当我要求AuthenticationMethod.FORMS而不是id 1时,我需要"FORMS"这个词.
我找到了以下解决此问题的方法(链接):
首先,我需要创建一个名为"StringValue"的自定义属性:
public class StringValue : System.Attribute
{
private readonly string _value;
public StringValue(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以将此属性添加到我的枚举器:
public enum AuthenticationMethod
{
[StringValue("FORMS")]
FORMS = 1,
[StringValue("WINDOWS")]
WINDOWSAUTHENTICATION = 2,
[StringValue("SSO")]
SINGLESIGNON = 3
}
Run Code Online (Sandbox Code Playgroud)
当然我需要一些东西来检索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;
}
}
Run Code Online (Sandbox Code Playgroud)
好现在我有了获取枚举器字符串值的工具.我可以这样使用它:
string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);
Run Code Online (Sandbox Code Playgroud)
好的,现在所有这些都像魅力一样,但我发现它做了很多工作.我想知道是否有更好的解决方案.
我也尝试过使用字典和静态属性的东西,但这也不是更好.
Jak*_*urc 862
尝试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;
}
}
Run Code Online (Sandbox Code Playgroud)
更新 显式(或隐式)类型转换可以通过
添加带映射的静态字段
private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
Run Code Online (Sandbox Code Playgroud)
在实例构造函数中填充此映射
instance[name] = this;
Run Code Online (Sandbox Code Playgroud)并添加用户定义的类型转换运算符
public static explicit operator AuthenticationMethod(string str)
{
AuthenticationMethod result;
if (instance.TryGetValue(str, out result))
return result;
else
throw new InvalidCastException();
}
Run Code Online (Sandbox Code Playgroud)Cha*_*ana 226
使用方法
Enum.GetName(Type MyEnumType, object enumvariable)
Run Code Online (Sandbox Code Playgroud)
如(假设Shipper是一个定义的枚举)
Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);
Run Code Online (Sandbox Code Playgroud)
Enum类还有很多其他静态方法值得研究......
Ben*_*ter 78
您可以使用ToString()引用名称而不是值
Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());
Run Code Online (Sandbox Code Playgroud)
文档在这里:
http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx
...如果你在Pascal Case中命名你的枚举(正如我所做的那样 - 例如ThisIsMyEnumValue = 1等),那么你可以使用一个非常简单的正则表达式来打印友好的形式:
static string ToFriendlyCase(this string EnumString)
{
return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}
Run Code Online (Sandbox Code Playgroud)
可以从任何字符串轻松调用:
Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());
Run Code Online (Sandbox Code Playgroud)
输出:
将我疯狂的帕斯卡案句转换为友好案例
这样可以节省在房屋周围的运行,创建自定义属性并将它们附加到您的枚举或使用查找表将枚举值与友好字符串结合,最重要的是它自我管理,并且可以在任何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;
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以直接从枚举实例中轻松访问它:
Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());
Run Code Online (Sandbox Code Playgroud)
Kei*_*ith 72
不幸的是,在枚举上获取属性的反射非常慢:
看到这个问题:任何人都知道快速获取枚举值的自定义属性的方法吗?
该.ToString()是枚举很慢了.
您可以为枚举编写扩展方法:
public static string GetName( this MyEnum input ) {
switch ( input ) {
case MyEnum.WINDOWSAUTHENTICATION:
return "Windows";
//and so on
}
}
Run Code Online (Sandbox Code Playgroud)
这不是很好,但会很快,不需要反映属性或字段名称.
C#6更新
如果您可以使用C#6,那么new nameof运算符适用于枚举,因此nameof(MyEnum.WINDOWSAUTHENTICATION)将"WINDOWSAUTHENTICATION"在编译时转换为,这使得它成为获取枚举名称的最快方法.
请注意,这会将显式枚举转换为内联常量,因此它不适用于变量中的枚举.所以:
nameof(AuthenticationMethod.FORMS) == "FORMS"
Run Code Online (Sandbox Code Playgroud)
但...
var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"
Run Code Online (Sandbox Code Playgroud)
Man*_*kar 59
我使用扩展方法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在用以下装饰enum:
public enum AuthenticationMethod
{
[Description("FORMS")]
FORMS = 1,
[Description("WINDOWSAUTHENTICATION")]
WINDOWSAUTHENTICATION = 2,
[Description("SINGLESIGNON ")]
SINGLESIGNON = 3
}
Run Code Online (Sandbox Code Playgroud)
你打电话的时候
AuthenticationMethod.FORMS.ToDescription()你会得到的"FORMS".
小智 41
只需使用该ToString()方法
public enum any{Tomato=0,Melon,Watermelon}
Run Code Online (Sandbox Code Playgroud)
要引用该字符串Tomato,只需使用
any.Tomato.ToString();
Run Code Online (Sandbox Code Playgroud)
小智 29
使用.Net 4.0及更高版本的解决方案非常简单.不需要其他代码.
public enum MyStatus
{
Active = 1,
Archived = 2
}
Run Code Online (Sandbox Code Playgroud)
要获取有关使用的字符串:
MyStatus.Active.ToString("f");
Run Code Online (Sandbox Code Playgroud)
要么
MyStatus.Archived.ToString("f");`
Run Code Online (Sandbox Code Playgroud)
该值将为"活动"或"已存档".
要在调用时Enum.ToString查看不同的字符串格式(上面的"f"),请参阅此枚举格式字符串页面
Ray*_*sen 28
我使用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();
}
Run Code Online (Sandbox Code Playgroud)
举个例子:
public enum Cycle : int
{
[Description("Daily Cycle")]
Daily = 1,
Weekly,
Monthly
}
Run Code Online (Sandbox Code Playgroud)
这段代码非常适合您不需要"友好名称"的枚举,并且只返回枚举的.ToString().
dea*_*dog 27
我真的很喜欢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");
}
Run Code Online (Sandbox Code Playgroud)
因此,您可以获得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;
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*ham 13
我结合上面的一些建议,结合一些缓存.现在,我从网上某处找到的一些代码中得到了这个想法,但我既不记得我在哪里找到它或者找到它.因此,如果有人发现类似的内容,请对归因进行评论.
无论如何,用法涉及类型转换器,所以如果你绑定到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
}
Run Code Online (Sandbox Code Playgroud)
自定义枚举类型转换器的代码如下:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
}
ILI*_*DNO 12
在你的问题中,你从未说过你实际上需要枚举的数值.
如果你不这样做,只需要一个类型字符串的枚举(这不是一个整数类型,所以不能作为枚举的基础)这里是一种方式:
static class AuthenticationMethod
{
public static readonly string
FORMS = "Forms",
WINDOWSAUTHENTICATION = "WindowsAuthentication";
}
Run Code Online (Sandbox Code Playgroud)
您可以使用与枚举相同的语法来引用它
if (bla == AuthenticationMethod.FORMS)
Run Code Online (Sandbox Code Playgroud)
它会比使用数值(比较字符串而不是数字)慢一点,但在正面,它不使用反射(慢)来访问字符串.
Loc*_*ith 11
作为大多数人,我真的很喜欢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); }
}
Run Code Online (Sandbox Code Playgroud)
这是基类:
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
}
Run Code Online (Sandbox Code Playgroud)
小智 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();
}
Run Code Online (Sandbox Code Playgroud)
枚举:
public enum OrderType
{
None = 0,
[Description("New Card")]
NewCard = 1,
[Description("Reload")]
Refill = 2
}
Run Code Online (Sandbox Code Playgroud)
用法(其中o.OrderType是与枚举同名的属性):
o.OrderType.GetDescription()
Run Code Online (Sandbox Code Playgroud)
这给了我一串"新卡"或"重新加载"而不是实际的枚举值NewCard和Refill.
Ton*_*llo 10
我同意基思,但我还不能投票.
我使用静态方法和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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,根据某些说法,这会导致可能的维护噩梦和一些代码味道.我试着留意那些很长很多枚举的词汇,或者经常变化的词汇.否则,这对我来说是一个很好的解决方案.
Gri*_*inn 10
如果你来这里寻求实现一个简单的"枚举"但其值是字符串而不是整数,这是最简单的解决方案:
public sealed class MetricValueList
{
public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
}
Run Code Online (Sandbox Code Playgroud)
执行:
var someStringVariable = MetricValueList.Brand;
Run Code Online (Sandbox Code Playgroud)
当我遇到这个问题时,有几个问题我试图先找到答案:
最简单的方法是使用Enum.GetValue(并支持使用round-tripping Enum.Parse).TypeConverter正如Steve Mitcham建议的那样,通常还需要建立一个支持UI绑定的方法.(TypeConverter当你使用属性表时,没有必要建立一个属性表,这是关于属性表的好处之一.虽然主知道他们有自己的问题.)
一般来说,如果上述问题的答案表明它不起作用,我的下一步是创建并填充一个静态的Dictionary<MyEnum, string>,或者可能是一个Dictionary<Type, Dictionary<int, string>>.我倾向于跳过中间装饰 - 代码与属性步骤,因为接下来通常会出现在长矛上的是需要在部署后更改友好值(通常,但并非总是如此,因为本地化).
我想发布这个作为对下面引用的帖子的评论,但不能,因为我没有足够的代表 - 所以请不要投票.代码包含错误,我想向尝试使用此解决方案的个人指出:
Run Code Online (Sandbox Code Playgroud)[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
}
Run Code Online (Sandbox Code Playgroud)
高明!
我创建了一个基类,用于在 .NET 中创建字符串值枚举。它只是一个 C# 文件,您可以将其复制并粘贴到您的项目中,或者通过名为StringEnum 的NuGet 包进行安装。 GitHub 仓库
<completitionlist>。(适用于 C# 和 VB)
///<completionlist cref="HexColor"/>
class HexColor : StringEnum<HexColor>
{
public static readonly HexColor Blue = Create("#FF0000");
public static readonly HexColor Green = Create("#00FF00");
public static readonly HexColor Red = Create("#000FF");
}
Run Code Online (Sandbox Code Playgroud)
// Static Parse Method
HexColor.Parse("#FF0000") // => HexColor.Red
HexColor.Parse("#ff0000", caseSensitive: false) // => HexColor.Red
HexColor.Parse("invalid") // => throws InvalidOperationException
// Static TryParse method.
HexColor.TryParse("#FF0000") // => HexColor.Red
HexColor.TryParse("#ff0000", caseSensitive: false) // => HexColor.Red
HexColor.TryParse("invalid") // => null
// Parse and TryParse returns the preexistent instances
object.ReferenceEquals(HexColor.Parse("#FF0000"), HexColor.Red) // => true
// Conversion from your `StringEnum` to `string`
string myString1 = HexColor.Red.ToString(); // => "#FF0000"
string myString2 = HexColor.Red; // => "#FF0000" (implicit cast)
Run Code Online (Sandbox Code Playgroud)
.Net Standard 1.0所以它在.Net Core>= 1.0、.Net Framework>= 4.5、Mono>= 4.6 等上运行。 /// <summary>
/// Base class for creating string-valued enums in .NET.<br/>
/// Provides static Parse() and TryParse() methods and implicit cast to string.
/// </summary>
/// <example>
/// <code>
/// class Color : StringEnum <Color>
/// {
/// public static readonly Color Blue = Create("Blue");
/// public static readonly Color Red = Create("Red");
/// public static readonly Color Green = Create("Green");
/// }
/// </code>
/// </example>
/// <typeparam name="T">The string-valued enum type. (i.e. class Color : StringEnum<Color>)</typeparam>
public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
{
protected string Value;
private static Dictionary<string, T> valueDict = new Dictionary<string, T>();
protected static T Create(string value)
{
if (value == null)
return null; // the null-valued instance is null.
var result = new T() { Value = value };
valueDict.Add(value, result);
return result;
}
public static implicit operator string(StringEnum<T> enumValue) => enumValue.Value;
public override string ToString() => Value;
public static bool operator !=(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value != o2?.Value;
public static bool operator ==(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value == o2?.Value;
public override bool Equals(object other) => this.Value.Equals((other as T)?.Value ?? (other as string));
bool IEquatable<T>.Equals(T other) => this.Value.Equals(other.Value);
public override int GetHashCode() => Value.GetHashCode();
/// <summary>
/// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else throws InvalidOperationException.
/// </summary>
/// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
/// <param name="caseSensitive">If true, the strings must match case and takes O(log n). False allows different case but is little bit slower (O(n))</param>
public static T Parse(string value, bool caseSensitive = true)
{
var result = TryParse(value, caseSensitive);
if (result == null)
throw new InvalidOperationException((value == null ? "null" : $"'{value}'") + $" is not a valid {typeof(T).Name}");
return result;
}
/// <summary>
/// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else returns null.
/// </summary>
/// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
/// <param name="caseSensitive">If true, the strings must match case. False allows different case but is slower: O(n)</param>
public static T TryParse(string value, bool caseSensitive = true)
{
if (value == null) return null;
if (valueDict.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
if (caseSensitive)
{
if (valueDict.TryGetValue(value, out T item))
return item;
else
return null;
}
else
{
// slower O(n) case insensitive search
return valueDict.FirstOrDefault(f => f.Key.Equals(value, StringComparison.OrdinalIgnoreCase)).Value;
// Why Ordinal? => https://esmithy.net/2007/10/15/why-stringcomparisonordinal-is-usually-the-right-choice/
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的变体
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;
}
}
Run Code Online (Sandbox Code Playgroud)
代码看起来有些丑陋,但是此结构的用法非常具有代表性。
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
Run Code Online (Sandbox Code Playgroud)
另外,我认为,如果需要大量此类枚举,则可以使用代码生成(例如T4)。
| 归档时间: |
|
| 查看次数: |
747996 次 |
| 最近记录: |