【问题标题】:Elegantly parsing C# Enums优雅地解析 C# 枚举
【发布时间】:2012-07-31 14:20:27
【问题描述】:

有没有人有更优雅的解析枚举的解决方案?以下对我来说似乎是一团糟。

UserType userType = (UserType)Enum.Parse(typeof(UserType), iUserType.ToString());

【问题讨论】:

    标签: c# enums


    【解决方案1】:

    我经常为它做一个通用的助手:

    public static T ParseEnum<T>(string value) where T:struct
    {
        return (T)Enum.Parse(typeof(T), value);
    }
    

    您可以将其与 Jon Skeet's Unstrained Melody(或任何其他 IL 后处理器)结合使用,以获得对枚举的正确类型约束,但这是可选的。

    那么你可以这样使用它:

    var enumValue = ParseEnum<UserType>(iUserType.ToString());
    

    .NET Framework 4.0 还附带了Enum.TryParse,它也提供了类似的语法,并提供了一种在解析失败时进行处理的方法。例如:

    UserType userType;
    if (Enum.TryParse<UserType>(iUserType.ToString(), out userType))
    {
        //Yay! Parse succeeded. The userType variable has the value.
    }
    else
    {
        //Oh noes! The parse failed!
    }
    

    【讨论】:

    • 我注意到对于 Enum.TryParse(),解析永远不会失败,即使我希望它用于不在枚举中的值。我的例子是:pastebin.com/fZfT69Lk
    • @Colin - 很有趣。这是因为整数值始终可以转换为枚举,例如(TestEnum)4737373 也可以工作和编译。如果你想强制你的值是一个命名值,你可以使用 GetNames 来确保它在那里。
    【解决方案2】:

    你可以像这样创建一个扩展方法

    public static class EnumExtensions
    {
        public static T ToEnum<T>(this string s)
        {
            return (T)Enum.Parse(typeof(T), s);
        }
    }
    

    然后在代码中你可以这样使用它(MyEnum 包含值 A 和 B):

    string s = "B";
    MyEnum e = s.ToEnum<MyEnum>();
    

    【讨论】:

      【解决方案3】:

      这是基于@vcsjones 版本和反馈的扩展方法,来自@Mones 示例:

      public enum TestEnum
      {
          None,
          A,
          B,
      };
      
      void Main()
      {
          var testValues = new List<object>();
          testValues.AddRange(Enumerable.Range(-2, 6).Select(i => (object)i));
          testValues.AddRange(new List<string>() { String.Empty, "A", "B", "C", null });
      
          foreach (var testValue in testValues)
          {
              Console.WriteLine($"Testing value {testValue ?? String.Empty}:");
              TestEnum output;
              var enumValues = Enum.GetNames(typeof(TestEnum)).ToList();
              try
              {
                  if (TestEnum.TryParse(testValue.ToString(), out output))
                  {
                      Console.WriteLine($"Succeeded with TryParse on {testValue} to {output}");
                  }
                  else
                  {
                      Console.WriteLine($"Failed to TryParse on {testValue}");
                  }
              }
              catch (Exception ex)
              {
                  Console.WriteLine($"Test harness caught an exception: {ex.ToString()}");
              }
      
              var toEnumOutput = (testValue ?? String.Empty).ToString().Parse<TestEnum>();
              Console.WriteLine($"Parse<TEnum> returned {toEnumOutput}");
      
              Console.WriteLine();
              Console.WriteLine();
          }
      
      }
      
      
      public static class EnumExtensions
      {
          public static TEnum Parse<TEnum>(this string value) where TEnum : struct
          {
              TEnum output = default(TEnum);
              var enumValues = Enum.GetNames(typeof(TEnum)).ToList();
      
              if (Enum.TryParse<TEnum>(value, true, out output))
                  if (Enum.IsDefined(typeof(TEnum), value) || value.ToString().Contains(",") || enumValues.Contains(output.ToString()))
                  {
                      Console.WriteLine($"Converted '{value}' to {output}.");
                      return output;
                  }
                  else
                  {
                      Console.WriteLine($"{value} is not an underlying value of the enumeration.");
                  }
              else
              {
                  Console.WriteLine($"{value} is not a member of the enumeration.");
              }
              return default(TEnum);
          }
      }
      

      测试工具给出以下输出:

      Testing value -2:
      Succeeded with TryParse on -2 to -2
      -2 is not an underlying value of the enumeration.
      Parse<TEnum> returned None
      
      
      Testing value -1:
      Succeeded with TryParse on -1 to -1
      -1 is not an underlying value of the enumeration.
      Parse<TEnum> returned None
      
      
      Testing value 0:
      Succeeded with TryParse on 0 to None
      Converted '0' to None.
      Parse<TEnum> returned None
      
      
      Testing value 1:
      Succeeded with TryParse on 1 to A
      Converted '1' to A.
      Parse<TEnum> returned A
      
      
      Testing value 2:
      Succeeded with TryParse on 2 to B
      Converted '2' to B.
      Parse<TEnum> returned B
      
      
      Testing value 3:
      Succeeded with TryParse on 3 to 3
      3 is not an underlying value of the enumeration.
      Parse<TEnum> returned None
      
      
      Testing value :
      Failed to TryParse on 
       is not a member of the enumeration.
      Parse<TEnum> returned None
      
      
      Testing value A:
      Succeeded with TryParse on A to A
      Converted 'A' to A.
      Parse<TEnum> returned A
      
      
      Testing value B:
      Succeeded with TryParse on B to B
      Converted 'B' to B.
      Parse<TEnum> returned B
      
      
      Testing value C:
      Failed to TryParse on C
      C is not a member of the enumeration.
      Parse<TEnum> returned None
      
      
      Testing value :
      Test harness caught an exception: System.NullReferenceException: Object reference not set to an instance of an object.
         at UserQuery.Main() in C:\Users\Colin\AppData\Local\Temp\3\LINQPad5\_zhvrhwll\query_ludjga.cs:line 49
       is not a member of the enumeration.
      Parse<TEnum> returned None
      

      参考资料:

      【讨论】:

      • 我看到您努力通过一组很好的测试创建一个经过充分研究的答案。这真的很棒,但让我鼓励你尝试使用一些单元测试框架。任何一个,这些年他们真的很相似。我很想用 xUnit 重写你的测试(我真的很喜欢那个,只需链接一个 nuget 就可以了)向你展示它有多酷/可读,但是.. 可能你自己做会受益更多。如果您想尝试并遇到问题,请给我留言。
      • 嗨@quetzalcoatl - 感谢您的反馈。我添加了 nUnit 测试,然后发布了一个指向我的测试类的链接。
      【解决方案4】:

      哦,我遇到了 Tyler Brinkley 的 Enums.NET 库,它可以做到这一点,甚至更多!

      另一个 StackOverflow 答案 Generic version of Enum.Parse in C# 导致 Jon Skeet 的 Unconstrained Melody 库站点,将我们引导到 Enums.NET。哇。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多