当前位置:  开发笔记 > 编程语言 > 正文

枚举的字符串表示形式

如何解决《枚举的字符串表示形式》经验,为你挑选了18个好方法。

我有以下枚举:

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

然而问题是,当我要求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; }
    }

}

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

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

好的,现在所有这些都像魅力一样,但我发现它做了很多工作.我想知道是否有更好的解决方案.

我也尝试过使用字典和静态属性的东西,但这也不是更好.



1> Jakub Šturc..:

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

}

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

添加带映射的静态字段

private static readonly Dictionary instance = new Dictionary();

nb为了在调用实例构造函数时初始化"枚举成员"字段不会抛出NullReferenceException,请确保将Dictionary字段放在类中的"枚举成员"字段之前.这是因为静态字段初始化程序是按声明顺序调用的,并且在静态构造函数之前,创建了奇怪且必要但令人困惑的情况,即在初始化所有静态字段之前,以及在调用静态构造函数之前,可以调用实例构造函数.

在实例构造函数中填充此映射

instance[name] = this;

并添加用户定义的类型转换运算符

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


@Ant:我没有.由于每个AuthenticationMethod只有一个实例,因此继承自Object的引用相等性能正常.
@Jakub非常有趣.我不得不玩它来弄清楚如何使用它,并实现它的好处.它是一个公共的非静态类,但无法实例化,您只能访问其静态成员.基本上,它的行为类似于枚举.但是最好的部分......静态成员是类的类型而不是通用字符串或int.这是... [等待它] ...键入安全枚举!谢谢你帮我理解.
它看起来像枚举,但它不是枚举.我可以想象如果人们开始尝试比较AuthenticationMethods会导致一些有趣的问题.您可能还需要重载各种相等运算符.
@tyriker:编译器.构造函数是私有的,因此您无法创建新实例.此外,静态成员无法通过实例访问.
@kiran我发布了一个稍微修改过的JakubŠturc的答案,它允许它与Switch-Case语句一起使用,所以现在这种方法没有任何缺点:)
喜欢这个解决方案 - 我遇到的唯一主要缺点是它在switch语句中不起作用 - 也就是说,我可以在交换机中使用普通枚举或const列表,但不是这些.
@MauricioScheffer:我可以争论退化,但你是对的.所有这一切都发生过,所有这一切都将再次发生.
我喜欢这个,你也可以在枚举上定义额外的方法,给出像分组行为的东西(比如DayOfTheWeek枚举的标准示例,使用IsWeekend方法,如果被引用的实例是星期六或星期日,则返回true).
@ssg:我已经更新了样本.所以现在如果你可以写var strongTypeInstance =(AuthenticationMethod)"FORMS"; 我不确定转换运算符.也许静态Parse方法会更好.如果你想要它你就可以得到它.
有关如何实现此模式的更多详细信息,请查看http://www.javacamp.org/designPattern/enum.html我知道它不是C#实现,但仍然可以理解.
我为之前评论中的光顾语气道歉.绝对不合适.它只是一个同义词......
@JakubŠturc关于这个机会,你会对此作出回应:我如何像枚举Enum.GetValues()那样枚举这个?我唯一能想到的是静态`Enumerate()`函数的反射.
太糟糕了,这不适用于Switch case语句,因为常量只允许作为大小写
喜欢这个模式,之前以多种形式使用它,但也许让我回到**Enums**的一件事就是我不能将这个TypeSafeEnum用作参数**的**默认值,因为它是_不是编译时常量_.围绕这个打嗝的任何想法?

2> Charles Bret..:

使用方法

Enum.GetName(Type MyEnumType,  object enumvariable)  

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

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

Enum类还有很多其他静态方法值得研究......


如果你需要一个具有额外功能的枚举,另一个选择是使用结构"滚动你自己"...你添加静态只读命名属性来表示初始化为生成结构的单个实例的构造函数的枚举值...
究竟.我确实为字符串描述创建了一个自定义属性,但这是因为我想要一个用户友好的版本(带有空格和其他特殊字符),可以很容易地绑定到ComboBox等.
Enum.GetName反映枚举中的字段名称 - 与.ToString()相同.如果性能是一个问题,它可能是一个问题.除非你转换大量的枚举,否则我不会担心它.
这里的问题是GetName不可本地化.这并不总是一个问题,但需要注意的是.

3> BenAlabaster..:

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

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

文档在这里:

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

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

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

输出:

将我疯狂的帕斯卡案句转换为友好案例

这样可以节省在房屋周围的运行,创建自定义属性并将它们附加到您的枚举或使用查找表将枚举值与友好字符串结合,最重要的是它自我管理,并且可以在任何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;
}

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

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


因此,请确保使用诸如FormsAuthentication之类的大写来命名枚举,并在任何不在开头的大写之前插入空格.在字符串中插入空格不是火箭科学......
Pascal Case名称的自动间隔如果包含应该大写的缩写,例如XML或GPS,则会出现问题.
如果"友好名称"需要空间,这无济于事.例如"表单身份验证"
@RichardEv,这里没有完美的正则表达式,但是这里的缩写应该会更好一些.`"(?!^)([^ AZ])([AZ])","$ 1 $ 2"`.所以`HereIsATEST`变成`这里是ATEST`.

4> Keith..:

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

看到这个问题:任何人都知道快速获取枚举值的自定义属性的方法吗?

.ToString()是枚举很慢了.

您可以为枚举编写扩展方法:

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

这不是很好,但会很快,不需要反映属性或字段名称.


C#6更新

如果您可以使用C#6,那么new nameof运算符适用于枚举,因此nameof(MyEnum.WINDOWSAUTHENTICATION)"WINDOWSAUTHENTICATION"编译时转换为,这使得它成为获取枚举名称的最快方法.

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

nameof(AuthenticationMethod.FORMS) == "FORMS"

但...

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


您可以获取属性值一次并将它们放在Dictionary 中以保留声明性方面.
@ user919426:实现想要吗?把它们放在字典里?只需创建一个字典,理想情况下使用集合初始化程序......目前还不清楚你要求的是什么.

5> Mangesh Pimp..:

我使用扩展方法:

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".


你在调用`AuthenticationMethod.FORMS.ToDescription()`时不是吗?

6> 小智..:

只需使用该ToString()方法

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

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

any.Tomato.ToString();


@Brent因为大多数情况下你的`.ToString()`值与你需要的用户友好值不同.
为什么其他人都过于复杂呢?
@Brent-因为这与所问的问题不同。所要问的问题是如何从分配了枚举值的变量中获取此字符串。在运行时这是动态的。这是在检查类型的定义并在运行时进行设置。

7> 小智..:

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

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

要获取有关使用的字符串:

MyStatus.Active.ToString("f");

要么

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

该值将为"活动"或"已存档".

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



8> Ray Booysen..:

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

public static string GetDescription(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().



9> deadlydog..:

我真的很喜欢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");
}

因此,您可以获得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;      
}



10> Steve Mitcha..:

我结合上面的一些建议,结合一些缓存.现在,我从网上某处找到的一些代码中得到了这个想法,但我既不记得我在哪里找到它或者找到它.因此,如果有人发现类似的内容,请对归因进行评论.

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

基本用法看起来像这样

[TypeConverter(typeof(CustomEnumTypeConverter))]
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 : EnumConverter
    where T : struct
{
    private static readonly Dictionary s_toString = 
      new Dictionary();

    private static readonly Dictionary s_toValue = 
      new Dictionary();

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

}



11> ILIA BROUDNO..:

在你的问题中,你从未说过你实际上需要枚举的数值.

如果你不这样做,只需要一个类型字符串的枚举(这不是一个整数类型,所以不能作为枚举的基础)这里是一种方式:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

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

if (bla == AuthenticationMethod.FORMS)

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



12> Lockszmith..:

作为大多数人,我真的很喜欢JakubŠturc选择的答案,但我也非常讨厌复制粘贴代码,并尽可能少地尝试.

所以我决定我想要一个EnumBase类,其中大部分功能都是继承/内置的,让我专注于内容而不是行为.

这种方法的主要问题是基于以下事实:虽然Enum值是类型安全的实例,但是交互是与Enum类类型的Static实现.所以在一点魔术的帮助下,我想我终于得到了正确的组合.希望有人发现这和我一样有用.

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

public sealed class AuthenticationMethod : EnumBase
{
    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 All
    { get { return EnumBase.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

这是基类:

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 where E: EnumBase
{
    #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> mapping;
    static EnumBase() { mapping = new Dictionary>(); }
    protected static E Parse(string name)
    {
        EnumBase 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 All
    { get { return mapping.Values.AsEnumerable().Cast(); } }
    #endregion
}



13> 小智..:

我如何解决这个扩展方法:

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

枚举:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

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

o.OrderType.GetDescription()

这给了我一串"新卡"或"重新加载"而不是实际的枚举值NewCard和Refill.


Bernie,DescriptionAttribute位于System.ComponentModel中

14> Tony Basallo..:

我同意基思,但我还不能投票.

我使用静态方法和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;
     }
}

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



15> Grinn..:

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

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

执行:

var someStringVariable = MetricValueList.Brand;


使变量变为consts而不是使用`static readonly`可能更好.

16> Robert Rossn..:

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

我的枚举值的名称是否足够友好,或者我是否需要提供更友好的名称?

我需要往返吗?也就是说,我需要获取文本值并将它们解析为枚举值吗?

这是我需要为我的项目中的许多枚举做的事情,还是仅仅一个?

我将在哪些UI元素中呈现此信息 - 特别是,我将绑定到UI,还是使用属性表?

这需要可本地化吗?

最简单的方法是使用Enum.GetValue(并支持使用round-tripping Enum.Parse).TypeConverter正如Steve Mitcham建议的那样,通常还需要建立一个支持UI绑定的方法.(TypeConverter当你使用属性表时,没有必要建立一个属性表,这是关于属性表的好处之一.虽然主知道他们有自己的问题.)

一般来说,如果上述问题的答案表明它不起作用,我的下一步是创建并填充一个静态的Dictionary,或者可能是一个Dictionary>.我倾向于跳过中间装饰 - 代码与属性步骤,因为接下来通常会出现在长矛上的是需要在部署后更改友好值(通常,但并非总是如此,因为本地化).



17> Paula Bean..:

我想发布这个作为对下面引用的帖子的评论,但不能,因为我没有足够的代表 - 所以请不要投票.代码包含错误,我想向尝试使用此解决方案的个人指出:

[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))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

高明!



18> Razoomnick..:

我的变体

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList 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() {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)。

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有