C#获取枚举值

时间:2009-06-17 16:11:37

标签: c# .net string enums

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

  • UnitedKingdom的,
  • UnitedStates的,
  • 法国,
  • 葡萄牙

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

这可能吗?

11 个答案:

答案 0 :(得分:53)

您无法为要开头的字符串指定枚举值。您必须致电ToString(),这会将Country.UnitedKingdom转换为“UnitedKingdom”。

两个选项表明自己:

  • 创建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));
    }
}

您可能希望将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();
}

然后你可以写:

string x = Country.UnitedKingdom.ToBriefName();

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

切换声明

我同意yshuditelu's answer建议在相对较少的情况下使用switch声明。但是,由于每个案例都是一个单一的陈述,我个人会改变我的编码风格,以保持代码紧凑但可读:

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

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

<强> DescriptionAttribute

关于DescriptionAttribute可重复使用的代码的Rado made点是一个好的,但在这种情况下,我建议每次需要获取值时都不要使用反射。我可能会编写一个通用的静态类来保存查找表(可能是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();
        }
    }
}

答案 1 :(得分:23)

我更喜欢在我的枚举上使用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;
}

然后获取我的绑定枚举列表,它只是调用

GetBoundEnum<MyCountryEnum>()

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

string whatever = MyCountryEnum.UnitedKingdom.GetDescription();

答案 2 :(得分:15)

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

示例:

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

答案 3 :(得分:6)

伪代码:

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

答案 4 :(得分:3)

未提及的另一种可能性是:

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

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

我认为在很多情况下,这种策略是最好的方法,但是在尝试将属性或属性添加到您希望能够将其视为枚举的内容时,可以选择注意这一点。

答案 5 :(得分:3)

我不得不把这项工作留在这个项目上一段时间了,回过头来,我有一点灵感。

而不是枚举,我创建了一个新的类:

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

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

我只是将此答案作为替代解决方案发布。

尼尔

答案 6 :(得分:2)

只需使用DescriptionAttribute

即可

如果只需要为枚举值获取字符串表示,则无需创建字典。见example

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

答案 7 :(得分:2)

我试图向Scott Ivey的回答提交一个编辑,但它被拒绝,这是另一个答案。我的编辑相对较少:

1)我修复了Alex System.ArgumentException: Field 'value__' defined on type 'MyClass.EnumHelperTest+MyCountryEnum' is not a field on the target object which is of type 'System.Reflection.RtFieldInfo'.here获得的错误。

2)添加了return,以便您可以实际复制/粘贴它,并且它可以正常工作。

3)将SortedDictionary更改为Dictionary,因为SortedDictionary总是按键排序,在本例中为字符串Description。没有理由按字母顺序排列描述。实际上,对它进行排序会破坏枚举的原始顺序。字典也不保留枚举顺序,但至少它并不像SortedDictionary那样暗示顺序。

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 Dictionary<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 Dictionary<string, T>();

    FieldInfo[] fieldInfos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);

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

答案 8 :(得分:1)

每当我看到枚举时,我都觉得应该重构代码。为什么不创建一个Country类并添加方法来做一些你想要解决的障碍。将值分配给枚举是一种更大的代码味道。

为什么会掉线?我认为使用多态方法比使用枚举更好被广泛接受。当您可以使用ValueObject设计时,没有理由使用枚举。

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

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