在C#中将枚举与字符串关联


361

我知道以下是不可能的,因为Enumeration的类型必须是int

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

从我的数据库中,我得到了一个不完整代码(the OEMCMBs)的字段。我想将此字段变成一个enum或其他可以理解的字段。因为如果目标是可读性,则解决方案应该简洁。

我还有什么其他选择?



12
我不确定为什么大多数答案都不会只使用“ const string”,而是在创建自定义类。
CTS_AE 2015年

1
您可能无法使用字符串,但是可以使用chars。如果可以使用单字母值,则可以选择该选项。
T. Sar

1
关于为什么CTS_AE上面提出的解决方案甚至不在前三个答案中的问题,确实感到困惑。
Sinjai'9

@Sinjai对相关值进行显式分组将大大超过无法察觉的性能损失,尤其是在API或可重用组件中。
person27年

Answers:


402

我喜欢在类而不是方法中使用属性,因为它们看起来更像枚举。

这是一个记录器的示例:

public class LogCategory
{
    private LogCategory(string value) { Value = value; }

    public string Value { get; set; }

    public static LogCategory Trace   { get { return new LogCategory("Trace"); } }
    public static LogCategory Debug   { get { return new LogCategory("Debug"); } }
    public static LogCategory Info    { get { return new LogCategory("Info"); } }
    public static LogCategory Warning { get { return new LogCategory("Warning"); } }
    public static LogCategory Error   { get { return new LogCategory("Error"); } }
}

传递类型安全的字符串值作为参数:

public static void Write(string message, LogCategory logCategory)
{
    var log = new LogEntry { Message = message };
    Logger.Write(log, logCategory.Value);
}

用法:

Logger.Write("This is almost like an enum.", LogCategory.Info);

4
我只能想出的缺点是它会慢一点,但这在大多数情况下可以忽略不计。并且它在编辑器中不会具有完全相同的行为。EG:切换这种情况不会自动为每种可能性填写案件。除了这些小问题,我认为这可能是一个相当简单的解决方案。
Boris Callens

3
使用Dictionary <LogCategory,Action / Func>作为开关很容易。:)
Arnis Lapsa 09年

4
@ArnisL。用作键还不够,您需要重写Equals()和GetHashCode(),并且要将Value属性设置器设为私有。不过,这不是一个枚举。
Dave Van den Eynde

21
供我自己使用,我扩展了此概念,并覆盖了ToStringreturn方法Value。然后为字符串提供隐式强制转换运算符。public static implicit operator String(LogCategory category) { return Value; }
Zarepheth 2014年

6
在开关箱中使用该怎么办?
大卫

176

您还可以使用扩展模型:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

您的延伸班

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

用法:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());

3
另请参见stackoverflow.com/questions/4367723/…,以获取扩展名以及从字符串到枚举的描述。
戴夫

14
我不禁想到,从性能的角度来看,每次要显示枚举时都要反映枚举听起来有些痛苦!
Liath 2014年

4
@Liath-`.ToString()`已经使用了反射,因此使用这种方法并不会造成任何损失,而是可以提高可读性
James King

1
您能否使扩展名通用,使其自动应用于所有枚举?
erosebe

3
为了使通用,使用public static string ToDescriptionString(this Enum ...ie而不显式键入MyEnum
LeeCambl

100

如何使用带有常量的静态类?

static class GroupTypes
{
  public const string TheGroup = "OEM";
  public const string TheOtherGroup = "CMB";
}

void DoSomething(string groupType)
{
  if(groupType == GroupTypes.TheGroup)
  {
    // Be nice
  }  
  else if (groupType == GroupTypes.TheOtherGroup)
  {
    // Continue to be nice
  }
  else
  {
    // unexpected, throw exception?
  }
}

9
同意 我很难看到更复杂的解决方案背后的目的,除了也许能够切换结果“枚举”。
fakeleft 2011年

@fakeleft您不能将静态类类型与泛型类型(模板)一起使用,并且可能还有其他限制,我认为这就是为什么人们喜欢“更复杂”的解决方案的原因。
eselk

2
常量必须是内部的或公共的,才能正常工作
arviman

46
静态类型不能用作参数。
Pedro Moreira

2
正如@PedroMoreira指出的那样,您不能将其GroupTypes作为参数类型传递,因为它是静态类。这就是Even Mien的答案所解决的问题。在这种情况下,您必须具有void DoSomething(string groupType),这意味着它groupType可以具有任何字符串值,甚至包括您不期望的值,这意味着您必须为那些无效的类型做好准备,并决定如何处理它们(例如引发异常)。甚至Mien的答案也可以通过将有效输入的数量限制为LogCategory类定义的选项来解决。
法拉普

30

您可以将属性添加到枚举中的项目,然后使用反射从属性中获取值。

您将必须使用“字段”说明符来应用属性,如下所示:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

然后,您将对枚举类型的静态字段(在本例中为GroupTypes)DescriptionAttribute进行反思,并使用反射获取要查找的值:

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);

    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");

    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);

    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);

    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

DescriptionAttribute如果您希望能够确定该属性是否已应用,则选择返回上面的自身。


尽管对于较复杂的情况我会记住这一点,但对于具有我在OP中所述的复杂性级别的情况而言,情况却相当复杂
Boris Callens 2012年

26

实际上,您可以轻松地做到这一点。使用以下代码。

enum GroupTypes
{
   OEM,
   CMB
};

然后,当您要获取每个枚举元素的字符串值时,只需使用以下代码即可。

String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);

过去,我已经成功使用了此方法,并且还使用了一个常量类来保存​​字符串常量,两者都工作得很好,但是我倾向于这种方法。


我在想同样的事情,但必须对此有所了解...否则,我会怀疑会有更多人建议这样做(也许我只是偏执)。
Matthijs Wessels,2010年

我唯一了解的是,我相信它使用反射来找出字符串。结果,如果我只是想跟踪一个常量字符串,那么我通常将使用一个类来存储大多数常量字符串。但是,如果我遇到了枚举是正确解决方案的情况(无论如何获取关于我的Enum元素的描述性字符串),那么与其使用多余的字符串来管理某个地方,不如使用上述枚举值。
Arthur C 2010年

+1这是最好和最简单的答案,在这里也有很高的投票证明这一点。最好使用扩展模型的唯一时间是当文本中需要空格时(此处有更多详细信息)。
SharpC

14
不,这只是获取枚举值的名称,而不是为枚举值分配字符串。OP的目标是使字符串不同于枚举值,例如:TheGroup =“ OEM”,TheOtherGroup =“ CMB”。
蒂姆·奥丁

3
我同意@Tim的评论,这不是 OP想要做的。如果您想知道这是什么用例,请考虑一种设备将字符串作为命令的情况,但也需要该命令的“人类可读”版本。我需要将“更新固件”与命令“ UPDATEFW”相关联。
JYelton'1

20

尝试将常量添加到静态类。您不会以Type结尾,但是您将拥有可读的,有组织的常量:

public static class GroupTypes {

    public const string TheGroup = "OEM";
    public const string TheOtherGroup = "CMB";

}

3
很难从代码返回到描述性名称。您将必须在所有const字段上使用反射来搜索匹配项。
andleer

1
@andleer我不明白您的担心。这是我使用的解决方案。
VSO

是的,这正是我想要的。这是我所看到的最简洁/优雅的解决方案,就好像我在定义带有w / int值的枚举-而是使用字符串值。100%完美。
乍得

3
这样做的问题是,在我们不会使用带有有限值列表的单独类型的意义上,它不能用作枚举。期望这些功能的函数可以与容易出错的自由格式字符串一起使用。
Juan Martinez

14

为您的数据库创建另一个枚举,其中包含以下内容:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

现在,您可以使用Enum.Parse从字符串“ OEM”和“ CMB”中检索正确的DBGroupTypes值。然后,您可以将其转换为int,并从要在模型中进一步使用的正确枚举中检索正确的值。


这似乎是过程中的一个额外步骤,为什么没有一个类可以处理所有事情呢?
C. Ross,2009年

11
而不是使用属性和反射?
Dave Van den Eynde 09年

13

使用课程。

编辑:更好的例子

class StarshipType
{
    private string _Name;
    private static List<StarshipType> _StarshipTypes = new List<StarshipType>();

    public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
    public static readonly StarshipType Light = new StarshipType("Light");
    public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
    public static readonly StarshipType Heavy = new StarshipType("Heavy");
    public static readonly StarshipType Superheavy = new StarshipType("Superheavy");

    public string Name
    {
        get { return _Name; }
        private set { _Name = value; }
    }

    public static IList<StarshipType> StarshipTypes
    {
        get { return _StarshipTypes; }
    }

    private StarshipType(string name, int systemRatio)
    {
        Name = name;
        _StarshipTypes.Add(this);
    }

    public static StarshipType Parse(string toParse)
    {
        foreach (StarshipType s in StarshipTypes)
        {
            if (toParse == s.Name)
                return s;
        }
        throw new FormatException("Could not parse string.");
    }
}

1
很难从代码返回到描述性名称。您将必须在所有const字段上使用反射来搜索匹配项。
andleer 2009年

1
我明白你的意思了。我将上传一个以后可以正常使用的版本,但我承认它很重。
C. Ross,2009年

我的版本基于C. Ross的解决方案stackoverflow.com/a/48441114/3862615
Roman M

7

解决该问题的另一种方法是拥有一个枚举和一个字符串数组,这些字符串将把枚举值与字符串列表进行映射:

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

string[] GroupTypesStr = {
    "OEM",
    "CMB"
};

您可以这样使用它:

Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);

它将提示CMB

优点:

  1. 简单而干净的代码。
  2. 高性能(特别是与使用类的那些方法相比)

缺点:

  1. 在编辑列表时容易弄乱列表,但是对于简短列表来说可以。

6

这是我用来获取枚举值作为字符串的扩展方法。首先是枚举。

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

Description属性来自System.ComponentModel。

这是我的扩展方法:

public static string GetValueAsString(this DatabaseEnvironment environment) 
{
    // get the field 
    var field = environment.GetType().GetField(environment.ToString());
    var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);

    if(customAttributes.Length > 0)
    {
        return (customAttributes[0] as DescriptionAttribute).Description;  
    }
    else
    {
        return environment.ToString(); 
    }
}

现在,您可以使用以下代码将枚举作为字符串值访问:

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}

5

您是否考虑过使用字典查找表?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

然后,可以在读取字符串时使用GroupTypeLookup.TryGetValue()查找字符串。


如何轻松获得给定值的密钥?
eglasius 2009年

这个问题并没有要求相反。但是,只要建立另一本反过来的字典就足够简单了。即,Dictionary <GroupTypes,string>。
Jim Mischel

4
public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;

    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");

    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }

    private DataType(string value)
    {
        this.value = value;
    }

    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;

        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;

        return predefinedValues[key];
    }

    public string Value
    {
        get { return value; }
    }
}

3

C#不支持枚举字符串,但是在大多数情况下,您可以使用列表或字典来获得所需的效果。

例如,要打印通过/失败结果:

List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);

2

我将其纳入一类,完全避免枚举。然后,通过使用类型处理程序,您可以在从数据库中获取对象时创建该对象。

IE浏览器:

public class Group
{
    public string Value{ get; set; }
    public Group( string value ){ Value = value; } 
    public static Group TheGroup() { return new Group("OEM"); }
    public static Group OtherGroup() { return new Group("CMB"); }

}

2

我只是创建一个字典,然后将代码用作键。

编辑:要解决有关进行反向查找(查找关键字)的评论,这将不会非常有效。如果有必要,我将编写一个新类来处理它。


您还可以轻松获取给定值的键吗?
eglasius 2009年

对于C.Ross-我不确定您的意思。您可以从db中读取值,并动态填充字典。
jhale

2

我的第一个问题-您是否有权访问数据库?最好在数据库中对此进行规范化,否则,任何解决方案都将容易出错。以我的经验,随着时间的流逝,充满“ OEM”和“ CMB”的数据域往往会混入诸如“ oem”和其他“废数据”之类的东西。如果可以对其进行规范化,则可以使用密钥在包含作为枚举的元素的表中,您已经完成了,并且结构更加简洁。

如果那不可用,我将创建您的Enum,并创建一个类以为您将字符串解析为Enum。与使用Enum.Parse / Reflection / etc进行任何变通方法相比,这至少将为您提供处理非标准条目的灵活性,并为捕获或处理错误提供更大的灵活性。字典可以工作,但是如果遇到案例问题,字典可能会崩溃。

我建议编写一个类,以便您可以执行以下操作:

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

这样可以保留大多数可读性,而无需更改数据库。


2

如果我理解正确,则需要从字符串转换为枚举:

enum GroupTypes {
    Unknown = 0,
    OEM = 1,
    CMB = 2
}
static GroupTypes StrToEnum(string str){
    GroupTypes g = GroupTypes.Unknown;
    try {
        object o = Enum.Parse(typeof(GroupTypes), str, true);
        g = (GroupTypes)(o ?? 0);
    } catch {
    }
    return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");

如果需要,可以使用泛型来枚举枚举类型。


2

在VS 2015中,您可以使用nameof

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

用法:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

2

对Glennular扩展方法进行了一些细微调整,因此您可以将扩展程序用于除ENUM之外的其他功能;

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

或使用Linq

using System;
using System.ComponentModel;
using System.Linq;

namespace Extensions {


public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}

2

遵循@Even Mien的回答后,我尝试更进一步并使其通用(Generic),我似乎差不多了,但仍然有一种情况可以抗拒,并且我可能可以简化我的代码。
如果有人看到我可以改进的地方,特别是使其无法工作,因为我无法从字符串中分配它,我将其张贴在这里

到目前为止,我得到以下结果:

        Console.WriteLine(TestEnum.Test1);//displays "TEST1"

        bool test = "TEST1" == TestEnum.Test1; //true

        var test2 = TestEnum.Test1; //is TestEnum and has value

        string test3 = TestEnum.Test1; //test3 = "TEST1"

        var test4 = TestEnum.Test1 == TestEnum.Test2; //false
         EnumType<TestEnum> test5 = "TEST1"; //works fine

        //TestEnum test5 = "string"; DOESN'T compile .... :(:(

魔术发生的地方:

public abstract  class EnumType<T>  where T : EnumType<T>   
{

    public  string Value { get; set; }

    protected EnumType(string value)
    {
        Value = value;
    }


    public static implicit operator EnumType<T>(string s)
    {
        if (All.Any(dt => dt.Value == s))
        {
            Type t = typeof(T);

            ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);

            return (T)ci.Invoke(new object[] {s});
        }
        else
        {
            return null;
        }
    }

    public static implicit operator string(EnumType<T> dt)
    {
        return dt?.Value;
    }


    public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
    {
        return (string)ct1 == (string)ct2;
    }

    public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
    {
        return !(ct1 == ct2);
    }


    public override bool Equals(object obj)
    {
        try
        {
            return (string)obj == Value;
        }
        catch
        {
            return false;
        }
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public static IEnumerable<T> All
     => typeof(T).GetProperties()
       .Where(p => p.PropertyType == typeof(T))
       .Select(x => (T)x.GetValue(null, null));



}

我只需要为我的枚举声明一下即可:

public class TestEnum : EnumType<TestEnum> 
{

    private TestEnum(string value) : base(value)
    {}

    public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
    public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}

感谢您所做的出色工作,我一直在寻找这种方法。我认为您应该为此获得1000分
user3492977

噢,谢谢您的评论,也谢谢您提醒我这一点,我在编写此代码段已有两年没有使用c#了,我应该尽快恢复使用!
Lomithrani

@ user3492977我终于回到它并使其充分functionnal,我仍然怀疑,虽然如果它是一个伟大的想法或无用的东西:d stackoverflow.com/questions/62043138/...
Lomithrani

2

.Net Core 3.0 / C#8.0中的新增功能(如果您的工作环境允许您升级项目)是一种简短的switch语句,看起来有些枚举。归根结底,这是我们多年以来一直在使用的旧无聊的switch语句。

这里唯一的真正区别是switch语句有了新的用法。

public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
    Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
    Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
    Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
    Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
    Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
    Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
    Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
    _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};

您会注意到,上面从此处复制的代码实际上是使用枚举作为参数。

这并不是您真正想要的(并且相信我,我一直想要类似于OP所要求的东西),但实际上我感觉这有点像MS的橄榄枝。JMO。

希望它能对某人有所帮助!


2

我使用了上一个答案中提到的结构,但是消除了任何复杂性。对我而言,这最像是创建字符串枚举。它的使用方式与枚举相同。

    struct ViewTypes
    {
        public const string View1 = "Whatever string you like";
        public const string View2 = "another string";
    }

使用示例:

   switch( some_string_variable )
   {
      case ViewTypes.View1: /* do something */ break;
      case ViewTypes.View2: /* do something else */ break;
   }

1

我什至按照@Even的建议(通过class Xpublic static X成员)实现了一些枚举,只是后来才发现,从.Net 4.5开始,这几天是正确的 ToString()方法。

现在,我将所有实现重新实现为枚举。


1

这是将其用作强类型参数或字符串的一种方式

public class ClassLikeEnum
{
    public string Value
    {
        get;
        private set;
    }

    ClassLikeEnum(string value) 
    {
        Value = value;
    }

    public static implicit operator string(ClassLikeEnum c)
    {
        return c.Value;
    }

    public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
    public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}

1

您可以使用两个枚举。一个用于数据库,另一个用于可读性。

您只需要确保它们保持同步即可,这似乎是很小的代价。您不必设置值,只需将位置设置为相同即可,但是设置值可以使两个枚举很明显地相互关联,并防止错误地重新排列枚举成员。并通过注释使维护人员知道这些相关并且必须保持同步。

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}

// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

要使用它,您只需先转换为代码:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

然后,如果您想使其更加方便,可以添加仅适用于此类枚举的扩展功能:

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

然后您可以执行以下操作:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();

这是一种不好的做法:在有一个从属的情况下,enum一个预期值的更改可能会无意间使另一个混乱。
劳伦斯·

1

我基本上是在寻找@ArthurC的思考答案

只需稍微扩展一下他的答案,您就可以通过使用泛型函数使其变得更好:

    // If you want for a specific Enum
    private static string EnumStringValue(GroupTypes e)
    {
        return EnumStringValue<GroupTypes>(e);
    }

    // Generic
    private static string EnumStringValue<T>(T enumInstance)
    {
        return Enum.GetName(typeof(T), enumInstance);
    } 

然后,您可以将任何东西包裹起来

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

要么

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic

1

摘自@EvenMien,并添加了一些评论。(也用于我自己的用例)

public struct AgentAction
{
    private AgentAction(string value) { Value = value; }

    public string Value { get; private set; }

    public override string ToString()
    {
        return this.Value;
    }

    public static AgentAction Login = new AgentAction("Logout");
    public static AgentAction Logout = new AgentAction("Logout");

    public static implicit operator string(AgentAction action) { return action.ToString(); }
}

1

添加课程

public class DatabasePreference {
    public DatabasePreference([CallerMemberName] string preferenceName = "") {
        PreferenceName = preferenceName;
    }
    public string PreferenceName;
}

这项工作正在使用 CallerMemberName用来最大程度地减少编码

使用:

//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();

测试一下:

Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);

输出:

ScannerDefaultFlashLight
Scanner1dCodes

0

根据其他意见,这就是我的想法。这种方法避免了在要获取常量值的位置键入.Value的方法。

我有一个像这样的所有字符串枚举的基类:

using System;
using Newtonsoft.Json;

[JsonConverter(typeof(ConstantConverter))]
public class StringEnum: IConvertible
{
    public string Value { get; set; }

    protected StringEnum(string value)
    {
        Value = value;
    }

    public static implicit operator string(StringEnum c)
    {
        return c.Value;
    }
    public string ToString(IFormatProvider provider)
    {
        return Value;
    }

    public TypeCode GetTypeCode()
    {
        throw new NotImplementedException();
    }

    public bool ToBoolean(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }
    //The same for all the rest of IConvertible methods
}

JsonConverter是这样的:

using System;
using Newtonsoft.Json;

class ConstantConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
        }
        else
        {
            serializer.Serialize(writer, value.ToString());
        }
    }
}

实际的字符串枚举将如下所示:

public sealed class Colors : StringEnum
{
    public static Colors Red { get { return new Catalog("Red"); } }
    public static Colors Yellow { get { return new Catalog("Yellow"); } }
    public static Colors White { get { return new Catalog("White"); } }

    private Colors(string value) : base(value) { }
}

有了这个,您可以使用Color.Red甚至序列化为json,而无需使用Value属性


0

我不需要像将字符串存储在属性中那样强大的功能。我只需要将类似的内容MyEnum.BillEveryWeek变成“每周收费”或MyEnum.UseLegacySystem“使用旧有系统”,基本上就是将骆驼的外壳分为小写的单个枚举。

public static string UnCamelCase(this Enum input, string delimiter = " ", bool preserveCasing = false)
{
    var characters = input.ToString().Select((x, i) =>
    {

       if (i > 0 && char.IsUpper(x))
       {
           return delimiter + x.ToString(CultureInfo.InvariantCulture);
       }
       return x.ToString(CultureInfo.InvariantCulture);

    });

    var result = preserveCasing
       ? string.Concat(characters)
       : string.Concat(characters).ToLower();

    var lastComma = result.LastIndexOf(", ", StringComparison.Ordinal);

    if (lastComma > -1)
    {
       result = result.Remove(lastComma, 2).Insert(lastComma, " and ");
    }

    return result;
}

MyEnum.UseLegacySystem.UnCamelCase() 输出“使用旧版系统”

如果设置了多个标志,它将变为纯英语(用逗号分隔,但用“和”代替最后一个逗号)。

var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes;

Console.WriteLine(myCustomerBehaviour.UnCamelCase());
//outputs "bill every week, use legacy system and charge taxes"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.