【问题标题】:What is the best way to strictly parse string to enum?将字符串严格解析为枚举的最佳方法是什么?
【发布时间】:2016-04-12 20:57:25
【问题描述】:

假设我有一个枚举:

public enum MyEnum
{
    OptionOne = 0,
    OptionTwo = 2,
    OptionThree = 4
}

就像在How should I convert a string to an enum in C#? 问题中所说的那样,我使用Enum.Parse 方法从字符串中解析枚举:

public class Enumer
{
    public static MyEnum? ParseEnum(string input)
    {
        try
        {
            return (MyEnum) Enum.Parse(typeof (MyEnum), input);
        }
        catch (ArgumentException)
        {
            return null;
        }
    }

}

不幸的是,对于表示为字符串的整数,它不能按预期工作。
我不希望 Parse.Enum() 将 int 从字符串转换,但实际上确实如此。
一个简单的测试:

[TestClass]
public class Tester
{
    [TestMethod]
    public void TestEnum()
    {
        Assert.AreEqual(MyEnum.OptionTwo, Enumer.ParseEnum("OptionTwo"));
        Assert.IsNull(Enumer.ParseEnum("WrongString"));
        Assert.IsNull(Enumer.ParseEnum("2")); // returns 2 instead of null
        Assert.IsNull(Enumer.ParseEnum("12345")); // returns 12345 instead of null
    }
}

只能通过四项中的两项检查。
Enumer.ParseEnum("2") 返回 MyEnum.OptionTwo 而不是 null
此外,Enumer.ParseEnum("12345") 返回 12345,不管它是否超出范围。

什么是最好的解析方式:

  1. 仅将“MyEnum.OptionOne”、“MyEnum.OptionTwo”、“MyEnum.OptionThree”的字符串值放入对应的枚举中。
  2. 字符串“MyEnum.OptionOne”、“MyEnum.OptionTwo”、“MyEnum.OptionThree”,并将 0、2 和 4 的值分别输入到 MyEnum.OptionOne、MyEnum.OptionTwo、MyEnum.OptionThree 中?

类似问题How should I convert a string to an enum in C#? 的链接对提供的测试没有帮助 - 它仍然将字符串转换为整数,即使它们超出了枚举范围。

【问题讨论】:

  • @ErkanDemirel,据我了解,这个问题是关于 Enum.Parse() 语法本身的。
  • @Kolky 你误解了这个问题。我不想将“12345”解析为 12345,但 Enum.Parse 可以。
  • 感觉你没看帖子。
  • 抱歉,误读了您最后的陈述。

标签: c# enums


【解决方案1】:

您可以使用Enum.GetValues(Type enumType) 自己完成此操作。

public static MyEnum? ParseEnum(string input)
{
    return (MyEnum?) Enum.GetValues(typeof(MyEnum)).OfType<object>()
                         .FirstOrDefault(v => v.ToString() == input);
}

添加对整数的支持,您也可以添加。

public static MyEnum? ParseEnum(string input)
{
    int value;
    var isInt = int.TryParse(input, out value);
    return (MyEnum?) Enum.GetValues(typeof(MyEnum)).OfType<object>()
                         .FirstOrDefault(v => v.ToString() == input
                                           || (isInt & (int)v == value));
}

由于我不能 100% 确定您的最后要求,因此我添加了一个包含名称且更通用的要求

public static T? ParseEnum<T>(string input)
    where T : struct 
{
    int value;
    var isInt = int.TryParse(input, out value);
    return (T?)Enum.GetValues(typeof(T)).OfType<object>()
                   .FirstOrDefault(v => v.ToString() == typeof(T).Name + input
                                    || (isInt & (int)v == value));
}

【讨论】:

  • 先转换成枚举再检查作用域不是更高效吗?
  • AFAIK 枚举方法 Parse()IsDefined() 使用反射,因为枚举只不过是具有 public const int OptionOne = 1 字段的类。因此,这应该具有相同的性能。如果你想有效地做到这一点,你应该创建一个 IDictionary&lt;string, MyEnum&gt;IDictionary&lt;int, MyEnum&gt; 并将其用于转换。
猜你喜欢
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 2015-06-14
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2017-04-04
  • 2011-09-05
相关资源
最近更新 更多