如何用字符串值定义枚举?

Sae*_*ani 81 c# string enums

我正在尝试定义Enum并添加在CSV或类似文件中使用的有效公共分隔符.然后我将它绑定到一个ComboBox数据源,所以每当我从Enum定义中添加或删除时,我都不需要在组合框中更改任何内容.

问题是我如何用字符串表示定义枚举,如:

public enum SeparatorChars{Comma = ",", Tab = "\t", Space = " "}

Jon*_*eet 104

你不能 - 枚举值必须是整数值.您可以使用属性将字符串值与每个枚举值相关联,或者在这种情况下,如果每个分隔符都是单个字符,则可以使用该char值:

enum Separator
{
    Comma = ',',
    Tab = '\t',
    Space = ' '
}
Run Code Online (Sandbox Code Playgroud)

(编辑:只是为了澄清,你不能创建char枚举的基础类型,但你可以使用char常量来分配对应于每个枚举值的整数值.上面枚举的基础类型是int.)

如果你需要一个扩展方法:

public string ToSeparatorString(this Separator separator)
{
    // TODO: validation
    return ((char) separator).ToString();
}
Run Code Online (Sandbox Code Playgroud)

  • @dowhilefor:根据我的回答,你可以使用char值为*值*.我测试了:) (6认同)
  • @JonSkeet 哦,您说得对,当然可以将它们转换为 int。没关系。 (2认同)
  • @ShaunLuttin:枚举只是“命名数字”-因此字符串枚举根本不适合该模型。 (2认同)

Mah*_*eep 70

据我所知,你不会被允许为枚举字符串赋值.你可以做的是创建一个包含字符串常量的类.

public static class SeparatorChars
{
    public static String Comma { get { return ",";} } 
    public static String Tab { get { return "\t,";} } 
    public static String Space { get { return " ";} } 
}
Run Code Online (Sandbox Code Playgroud)

  • 与其他人相反的这种方法的缺点是你不能在不做额外/特殊的事情的情况下列举这些. (7认同)
  • 这无助于在编译期间强制执行某些值,因为“separator”现在是一个字符串(可以是任何内容),而不是具有受限有效值的“Separator”类型。 (2认同)

Ami*_*rma 59

你可以实现它,但需要一点工作.

  1. 定义一个属性类,它将包含枚举的字符串值.
  2. 定义一个扩展方法,该方法将从属性返回值.Eg..GetStringValue(此枚举值)将返回属性值.
  3. 然后你可以像这样定义枚举..
public enum Test : int {
    [StringValue("a")]
    Foo = 1,
    [StringValue("b")]
    Something = 2        
} 
  1. 从Attrinbute Test.Foo.GetStringValue()获取值;

请参阅:使用C#中的字符串值枚举

  • 仅供参考,我多年前在 Nuget 包中实现了这个精确的解决方案,因此您可以 JustUseIt 而不必担心实现支持属性和访问器方法(加上我添加了一些性能改进和一些额外的花哨功能):D Nuget 包:https: //www.nuget.org/packages/EnumStringValues/ (3认同)
  • 我知道这个年代很久,但是它显然是唯一的,它允许您在数据库的代码和字符串值中使用枚举。惊人 (2认同)
  • 另一个迟到的评论,但这确实是一个出色的解决方案 (2认同)
  • 请记住反射对性能的影响(如果这与您的情况相关)。 (2认同)
  • 绝对令人惊奇的答案!喜欢简单的实施。 (2认同)

Fis*_*aen 27

您无法使用枚举执行此操作,但您可以这样做:

public static class SeparatorChars
{
    public static string Comma = ",";

    public static string Tab = "\t";

    public static string Space = " ";
}
Run Code Online (Sandbox Code Playgroud)

  • 我会使用`const`而不是`static`.常量是只读的,也是静态的,并且在构造函数中是不可忽略的(除非是只读字段). (6认同)

小智 25

对于字符串值(或任何其他类型)的简单枚举:

public static class MyEnumClass
{
    public const string 
        MyValue1 = "My value 1",
        MyValue2 = "My value 2";
}
Run Code Online (Sandbox Code Playgroud)

用法: string MyValue = MyEnumClass.MyValue1;

  • 虽然这不是枚举,但我认为这可能为用户尝试做的事情提供最佳解决方案。有时,最简单的解决方案是最好的。 (4认同)

Jav*_*ras 19

也许为时已晚,但它来了。

我们可以使用属性 EnumMember 来管理 Enum 值。

public enum EUnitOfMeasure
{
    [EnumMember(Value = "KM")]
    Kilometer,
    [EnumMember(Value = "MI")]
    Miles
}
Run Code Online (Sandbox Code Playgroud)

这样 EUnitOfMeasure 的结果值将是 KM 或 MI。这也可以从 Andrew Whitaker 的回答中看出。

  • 除了在序列化期间之外,它不起作用,而序列化只是枚举使用的一小部分。我想知道有多少赞成票是由于 6 分钟后锁定投票而产生的。 (4认同)

Ada*_*dam 12

你不能,因为枚举只能基于原始数字类型.您可以尝试使用Dictionary代替:

Dictionary<String, char> separators = new Dictionary<string, char>
{
    {"Comma", ','}, 
    {"Tab",  '\t'}, 
    {"Space", ' '},
};
Run Code Online (Sandbox Code Playgroud)

或者,你可以使用一个Dictionary<Separator, char>Dictionary<Separator, string>那里Separator是一个正常的枚举:

enum Separator
{
    Comma,
    Tab,
    Space
}
Run Code Online (Sandbox Code Playgroud)

这比直接处理字符串要愉快一些.


col*_*mde 8

模拟枚举行为但使用string而不是使用的类int可以创建如下...

public class GrainType
{
    private string _typeKeyWord;

    private GrainType(string typeKeyWord)
    {
        _typeKeyWord = typeKeyWord;
    }

    public override string ToString()
    {
        return _typeKeyWord;
    }

    public static GrainType Wheat = new GrainType("GT_WHEAT");
    public static GrainType Corn = new GrainType("GT_CORN");
    public static GrainType Rice = new GrainType("GT_RICE");
    public static GrainType Barley = new GrainType("GT_BARLEY");

}
Run Code Online (Sandbox Code Playgroud)

用法...

GrainType myGrain = GrainType.Wheat;

PrintGrainKeyword(myGrain);
Run Code Online (Sandbox Code Playgroud)

然后...

public void PrintGrainKeyword(GrainType grain) 
{
    Console.Writeline("My Grain code is " + grain.ToString());   // Displays "My Grain code is GT_WHEAT"
}
Run Code Online (Sandbox Code Playgroud)


suc*_*oss 7

答案有点晚了,但也许将来会对某人有所帮助。我发现将struct用于此类问题更容易。

以下示例是从MS代码复制粘贴的部分:

namespace System.IdentityModel.Tokens.Jwt
{
    //
    // Summary:
    //     List of registered claims from different sources http://tools.ietf.org/html/rfc7519#section-4
    //     http://openid.net/specs/openid-connect-core-1_0.html#IDToken
    public struct JwtRegisteredClaimNames
    {
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Actort = "actort";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Typ = "typ";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Sub = "sub";
        //
        // Summary:
        //     http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
        public const string Sid = "sid";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Prn = "prn";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nbf = "nbf";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nonce = "nonce";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string NameId = "nameid";

    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您能否解释一下为什么这种方法比使用类更好? (3认同)
  • @GerardoGrignoli 我不太清楚为什么他们在 MS 中使用 struct 而不是 class 来做这种事情。我什至没有试图找出答案,因为这对我来说非常有用。也许尝试在堆栈上提问...... (2认同)
  • 我知道它是从旧示例中复制/粘贴的。我只是提供新的指导方针,因此人们不会认为这些信息仍然正确。请参阅我上面提供的链接,了解有关此答案为何不符合当前指南的更多信息。 (2认同)

Zod*_*man 7

对于到达这里寻找更通用问题答案的人,如果您希望代码看起来像enum.

当您尚未最终确定enum names您想要的并且enum values是 的string表示时,以下方法有效enam name;用于nameof()使您的重构更简单。

public static class Colours
{
    public static string Red => nameof(Red);
    public static string Green => nameof(Green);
    public static string Blue => nameof(Blue);
}
Run Code Online (Sandbox Code Playgroud)

这实现了具有字符串值的枚举的意图(例如以下伪代码):

public enum Colours
{
    "Red",
    "Green",
    "Blue"
}
Run Code Online (Sandbox Code Playgroud)


Ger*_*oli 5

我创建了一个基类,用于在 .NET 中创建字符串值枚举。它只是一个 C# 文件,您可以将其复制并粘贴到项目中,或通过名为StringEnum的 NuGet 包进行安装。

用法:

///<completionlist cref="HexColor"/> 
class HexColor : StringEnum<HexColor>
{
    public static readonly HexColor Blue = New("#FF0000");
    public static readonly HexColor Green = New("#00FF00");
    public static readonly HexColor Red = New("#000FF");
}
Run Code Online (Sandbox Code Playgroud)

特征

  • 您的 StringEnum 看起来有点类似于常规枚举:
    // 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)
  • 如果该类使用 xml 注释进行注释,则 Intellisense 将建议枚举名称<completitionlist>。(适用于 C# 和 VB):即

智能感知演示

安装

任何一个:

  • 安装最新的StringEnum NuGet 包,它基于>= 1.0、>= 4.5、>= 4.6 等.Net Standard 1.0运行。.Net Core.Net FrameworkMono
  • 或者将以下 StringEnum 基类粘贴到您的项目中。(最新版本
    public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
    {
        protected string Value;
        private static IList<T> valueList = new List<T>();
        protected static T New(string value)
        {
            if (value == null)
                return null; // the null-valued instance is null.

            var result = new T() { Value = value };
            valueList.Add(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 sensitivity.</param>
        public static T Parse(string value, bool caseSensitive = false)
        {
            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 sensitivity.</param>
        public static T TryParse(string value, bool caseSensitive = false)
        {
            if (value == null) return null;
            if (valueList.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
            var field = valueList.FirstOrDefault(f => f.Value.Equals(value,
                    caseSensitive ? StringComparison.Ordinal
                                  : StringComparison.OrdinalIgnoreCase));
            // Not using InvariantCulture because it's only supported in NETStandard >= 2.0

            if (field == null)
                return null;

            return field;
        }
    }
Run Code Online (Sandbox Code Playgroud)
  • 对于Newtonsoft.Json序列化支持,请复制此扩展版本。StringEnum.cs

后来我意识到这段代码与 Ben 的答案类似。我是真心实意地从头开始写的。不过我认为它有一些额外的功能,比如<completitionlist>hack,生成的类看起来更像是一个 Enum,没有使用 Parse() 上的反射,NuGet 包和存储库,我希望能够解决传入的问题和反馈。