C# 获取枚举值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1008090/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:23:54  来源:igfitidea点击:

C# Getting Enum values

c#.netstringenums

提问by neildeadman

I have a enum containing the following (for example):

我有一个包含以下内容的枚举(例如):

  • UnitedKingdom,
  • UnitedStates,
  • France,
  • Portugal
  • 英国,
  • 美国,
  • 法国,
  • 葡萄牙

In my code I use Country.UnitedKingdombut I want to have the value be UKif I assign it to a stringfor example.

在我的代码中,我使用Country.UnitedKingdom但如果我将它分配给一个字符串,我希望它的值为UK

Is this possible?

这可能吗?

采纳答案by Jon Skeet

You can't assign an enum value to a string to start with. You'd have to call ToString(), which would convert Country.UnitedKingdomto "UnitedKingdom".

您不能将枚举值分配给要开始的字符串。您必须调用ToString(),它会转换Country.UnitedKingdom为“UnitedKingdom”。

Two options suggest themselves:

两种选择建议自己:

  • Create a Dictionary<Country, string>
  • A switch statement
  • Decorate each value with an attribute, and load that with reflection
  • 创建一个 Dictionary<Country, string>
  • 一个 switch 语句
  • 用一个属性装饰每个值,并用反射加载它

Comments about each of them...

对每个人的评论...

Sample code for Dictionary<Country,string>

示例代码 Dictionary<Country,string>

using System;
using System.Collections.Generic;

enum Country
{
    UnitedKingdom, 
    UnitedStates,
    France,
    Portugal
}

class Test
{
    static readonly Dictionary<Country, string> CountryNames =
        new Dictionary<Country, string>
    {
        { Country.UnitedKingdom, "UK" },
        { Country.UnitedStates, "US" },
    };

    static string ConvertCountry(Country country) 
    {
        string name;
        return (CountryNames.TryGetValue(country, out name))
            ? name : country.ToString();
    }

    static void Main()
    {
        Console.WriteLine(ConvertCountry(Country.UnitedKingdom));
        Console.WriteLine(ConvertCountry(Country.UnitedStates));
        Console.WriteLine(ConvertCountry(Country.France));
    }
}

You might want to put the logic of ConvertCountryinto an extension method. For example:

您可能希望将 的逻辑ConvertCountry放入扩展方法中。例如:

// Put this in a non-nested static class
public static string ToBriefName(this Country country) 
{
    string name;
    return (CountryNames.TryGetValue(country, out name))
        ? name : country.ToString();
}

Then you could write:

然后你可以写:

string x = Country.UnitedKingdom.ToBriefName();

As mentioned in the comments, the default dictionary comparer will involve boxing, which is non-ideal. For a one-off, I'd live with that until I found it was a bottleneck. If I were doing this for multiple enums, I'd write a reusable class.

如评论中所述,默认字典比较器将涉及装箱,这是不理想的。对于一次性的,我会忍受它,直到我发现它是一个瓶颈。如果我为多个枚举做这个,我会写一个可重用的类。

Switch statement

开关语句

I agree with yshuditelu's answersuggesting using a switchstatement for relatively few cases. However, as each case is going to be a single statement, I'd personally change my coding style for this situation, to keep the code compact but readable:

我同意yshuditelu 的回答,建议switch在相对较少的情况下使用声明。但是,由于每种情况都将是一个单独的语句,因此我个人会针对这种情况更改我的编码风格,以保持代码紧凑但可读:

public static string ToBriefName(this Country country) 
{
    switch (country)
    {
        case Country.UnitedKingdom:  return "UK";
        case Country.UnitedStates:   return "US";
        default:                     return country.ToString();
    }
}

You can add more cases to this without it getting too huge, and it's easy to cast your eyes across from enum value to the return value.

您可以为此添加更多案例而不会变得太大,并且很容易将您的目光从枚举值转移到返回值。

DescriptionAttribute

DescriptionAttribute

The point Rado madeabout the code for DescriptionAttributebeing reusable is a good one, but in that case I'd recommend against using reflection every time you need to get a value. I'd probably write a generic static class to hold a lookup table (probably a Dictionary, possibly with a custom comparer as mentioned in the comments). Extension methods can't be defined in generic classes, so you'd probably end up with something like:

Rado关于DescriptionAttribute可重用代码的观点是一个很好的观点,但在这种情况下,我建议不要在每次需要获取值时使用反射。我可能会编写一个通用静态类来保存查找表(可能是一个Dictionary,可能带有评论中提到的自定义比较器)。扩展方法不能在泛型类中定义,所以你可能会得到类似的结果:

public static class EnumExtensions
{
    public static string ToDescription<T>(this T value) where T : struct
    {
        return DescriptionLookup<T>.GetDescription(value);
    }

    private static class DescriptionLookup<T> where T : struct
    {
        static readonly Dictionary<T, string> Descriptions;

        static DescriptionLookup()
        {
            // Initialize Descriptions here, and probably check
            // that T is an enum
        }

        internal static string GetDescription(T value)
        {
            string description;
            return Descriptions.TryGetValue(value, out description)
                ? description : value.ToString();
        }
    }
}

回答by rein

Pseudo code:

伪代码:

enum MyCountryEnum
{
    UnitedKingdom = 0,
    UnitedStates = 1,
    France = 2,
    Portugal = 3,
}

string[] shortCodes = new string[] {"UK", "US", "FR", "PO"};


MyCountryEnum enumValue = MyCountryEnum.UnitedKingdom;
string code = shortCodes[enumValue];

回答by Timothy Carter

You could create an extension method public static string ToShortString(this Country country). In the method you could use either a static Dictionary as Jon suggests, or you could simply do a switch case.

您可以创建一个扩展方法public static string ToShortString(this Country country)。在该方法中,您可以使用 Jon 建议的静态字典,或者您可以简单地执行 switch case。

Example:

例子:

public static class CountryExtensions
{
    public static string ToShortString( this Country target )
    {
        switch (target) {
            case Country.UnitedKingdom:
                return "UK";
            case Country.UnitedStates:
                return "US";
            case Country.France:
                return "FR";
            case Country.Portugal:
                return "PT";
            default:
                return "None";
        }
    }
}

回答by Rado

Just use the DescriptionAttribute

只需使用DescriptionAttribute

No need to create a dictionary if you only need to get a String representation for your enum values. See this example

如果您只需要获取枚举值的字符串表示,则无需创建字典。看这个例子

[EDIT] Oh ... forgot to mention that it is more reusable than dictionaries, since you only need one common util class to help with getting the description and then all you need to do is add the DescriptionAttribute next time you add an enum value or you create a new enum with the same requirements. In the dictionary/switch solution, it is harder to maintain and it gets messy once you have many enum types.

[编辑] 哦...忘了提到它比字典更可重用,因为您只需要一个通用的 util 类来帮助获取描述,然后您需要做的就是在下次添加枚举值时添加 DescriptionAttribute或者您创建一个具有相同要求的新枚举。在字典/开关解决方案中,很难维护并且一旦您有许多枚举类型就会变得混乱。

回答by BlackTigerX

var codes = new Dictionary<Country, string>() 
        { { Country.UnitedKingdom, "UK" },
        { Country.UnitedStates, "US" },
        { Country.France, "FR" } };
Console.WriteLine(codes[Country.UnitedStates]);

回答by Scott Ivey

I prefer to use the DescriptionAttributeon my enums. Then, you can use the following code to grab that description from the enum.

我更喜欢在我的枚举上使用DescriptionAttribute。然后,您可以使用以下代码从枚举中获取该描述。

enum MyCountryEnum
{    
    [Description("UK")]
    UnitedKingdom = 0,    

    [Description("US")]
    UnitedStates = 1,    

    [Description("FR")]
    France = 2,    

    [Description("PO")]
    Portugal = 3
}

public static string GetDescription(this Enum value)
{
    var type = value.GetType();

    var fi = type.GetField(value.ToString());

    var descriptions = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];

    return descriptions.Length > 0 ? descriptions[0].Description : value.ToString();
}

public static SortedDictionary<string, T> GetBoundEnum<T>() where T : struct, IConvertible
{
    // validate.
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("T must be an Enum type.");
    }

    var results = new SortedDictionary<string, T>();

    FieldInfo[] fieldInfos = typeof(T).GetFields();

    foreach (var fi in fieldInfos)
    {

        var value = (T)fi.GetValue(fi);
        var description = GetDescription((Enum)fi.GetValue(fi));

        if (!results.ContainsKey(description))
        {
            results.Add(description, value);
        }
    }
    return results;
}

And then to get my bound enum list, its simply a call to

然后为了得到我绑定的枚举列表,它只是调用

GetBoundEnum<MyCountryEnum>()

To get a single enum's description, you'd just use the extension method like this

要获得单个枚举的描述,您只需使用这样的扩展方法

string whatever = MyCountryEnum.UnitedKingdom.GetDescription();

回答by Bryan Rowe

Whenever I see an enum I feel that the code should be refactored. Why not make a Country class and add methods to do some of the obstacles you are trying to get around. Assigning values to an enum is an even bigger code smell.

每当我看到枚举时,我都觉得应该重构代码。为什么不创建一个 Country 类并添加方法来解决您试图绕过的一些障碍。为枚举赋值是一种更大的代码味道。

Why the downvotes? I think it is pretty widely accepted that using a polymorphic approach is better than using an enum. There is zero reason to use an enum when you can use the ValueObject design instead.

为什么投反对票?我认为使用多态方法比使用枚举更好这一点已被广泛接受。当您可以使用 ValueObject 设计时,使用枚举的理由为零。

Here is a good blog post on the topic: http://devpinoy.org/blogs/cruizer/archive/2007/09/12/enums-are-evil.aspx

这是关于该主题的一篇很好的博客文章:http: //devpinoy.org/blogs/cruizer/archive/2007/09/12/enums-are-evil.aspx

回答by Klinger

The following solution works (compiles and runs). I see two issues:

以下解决方案有效(编译并运行)。我看到两个问题:

  1. You would have to make sure the enums are in sync. (An automated test can do that for you.)

  2. You would be relying in the fact that enums are not type safe in .NET.

    enum Country
    {
        UnitedKingdom = 0,
        UnitedStates = 1,
        France = 2,
        Portugal = 3
    }
    
    enum CountryCode
    {
        UK = 0,
        US = 1,
        FR = 2,
        PT = 3
    }
    
    void Main()
    {
        string countryCode = ((CountryCode)Country.UnitedKingdom).ToString();
        Console.WriteLine(countryCode);
        countryCode = ((CountryCode)Country.Portugal).ToString();
        Console.WriteLine(countryCode);
    }
    
  1. 您必须确保枚举是同步的。(自动化测试可以为您做到这一点。)

  2. 您将依赖于枚举在 .NET 中不是类型安全的事实。

    enum Country
    {
        UnitedKingdom = 0,
        UnitedStates = 1,
        France = 2,
        Portugal = 3
    }
    
    enum CountryCode
    {
        UK = 0,
        US = 1,
        FR = 2,
        PT = 3
    }
    
    void Main()
    {
        string countryCode = ((CountryCode)Country.UnitedKingdom).ToString();
        Console.WriteLine(countryCode);
        countryCode = ((CountryCode)Country.Portugal).ToString();
        Console.WriteLine(countryCode);
    }
    

回答by Timothy Carter

One other possibility that hasn't been mentioned is something like this:

另一种没有提到的可能性是这样的:

public class Country
{
    public static readonly Country UnitedKingdom = new Country("UK");
    public static readonly Country UnitedStates = new Country("US");
    public static readonly Country France = new Country("FR");
    public static readonly Country Protugal = new Country("PT");

    private Country(string shortName)
    {
        ShortName = shortName;
    }

    public string ShortName { get; private set; }
}

From this point you could add more properties, but beware of how much you add to the class, and how many static members you add, as the memory bloat it adds could make it not worth it.

从这一点开始,您可以添加更多属性,但要注意向类添加了多少,以及添加了多少静态成员,因为它添加的内存膨胀可能使其变得不值得。

I don't think there are many cases where this strategy is the best approach, but it is an option to be aware of when attempting to add properties or attributes to something you want to be able to treat as essentially an enum.

我不认为在很多情况下这种策略是最好的方法,但在尝试将属性或属性添加到您希望能够基本上视为枚举的内容时,这是一个需要注意的选项。

回答by neildeadman

I had to leave my work on this project for a while, and having come back to it, I had a moment of inspiration.

我不得不暂时放弃我在这个项目上的工作,回到它之后,我有片刻的灵感。

Rather than an enum, I created a new class like so:

而不是枚举,我创建了一个新类,如下所示:

public class Country
{
    public const string UnitedKingdom = "UK";
    public const string France = "F";
}

This way I can use Country.UnitedKingdom in my code and the value "UK" will be used.

这样我就可以在我的代码中使用 Country.UnitedKingdom 并且将使用值“UK”。

I'm just posting this answer as an alternative solution.

我只是发布这个答案作为替代解决方案。

Neil

尼尔