【问题标题】:Convert Enum to String将枚举转换为字符串
【发布时间】:2010-10-03 18:49:17
【问题描述】:

在 .NET 3.5 中将枚举转换为字符串的首选方法是什么?

  • Enum.GetName
  • 枚举格式
  • ToString

为什么我应该更喜欢其中一个而不是其他?一个表现更好吗?

【问题讨论】:

  • 我搜索并找不到重复项。如果您可以提供链接,我将删除此问题。
  • 有时,使用 switch 语句不是最佳实践(当您有大量枚举时)您可以使用 Dict 代替
  • 如果您想要更好的性能,您可以使用本文中描述的类codeproject.com/KB/dotnet/enum.aspx。用法看起来像这样 Enum.ToString(yourValue) 或 Enum.ToString((int)yourValue)
  • 编码不破坏dotfuscation是尾巴摇摆狗的缩影。 SW 制作人并没有想,“让我们做一个很棒的应用程序,让 dotfuscator 有事可做。” Dofuscator 的存在是为了帮助促进软件开发。如果它做不到……可以吗!

标签: .net enums


【解决方案1】:

从 C#6 开始,获取枚举名称的最佳方法是新的 nameof 运算符:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

这在编译时有效,枚举被编译结果中的字符串替换,这反过来意味着这是最快的方式。

如果您认为枚举名称的混淆是值得或重要的,那么任何枚举名称的使用都会干扰代码混淆 - 这可能是另一个问题。

【讨论】:

  • 这值得更多关注。尽管存在明显的限制,即编译时输入的要求。在我看来,这应该是首选尽可能。 “重命名”和“查找所有引用”也将其考虑在内,可能会避免魔术字符串和重复常量。
  • 所以我猜在运行时定义枚举值时它不起作用?例如:MyEnum 变量枚举; variableEnum = setEnumValueMethod(); nameof(variableEnum);
  • @Maxter no,因为nameof(variableEnum) 将是"variableEnum"。它反映(在构建时)字段/属性/参数/变量的 name 而不是 value
  • @Squibly 是的,这将返回"someEnumValue",而您需要nameof(SomeEnum.FooBar) 才能获得"FooBar"
  • 比我以前用的好多了:Enum.GetName(typeof(EnumType),instanceOfEnum)bleugh
【解决方案2】:

适用于我们的项目...

public static String convertToString(this Enum eff)
{
    return Enum.GetName(eff.GetType(), eff);
}

public static EnumType converToEnum<EnumType>(this String enumValue)  
{
    return (EnumType) Enum.Parse(typeof(EnumType), enumValue);
}

【讨论】:

  • Enum.GetName 将值作为对象参数。这意味着该值将被装箱,这将在分配和垃圾收集上浪费 CPU 资源。如果这样做很长时间,Enum.GetName 的吞吐量将比在字典中缓存值并在那里查找名称要低得多。
  • @Ran 那么解决方案是什么,改用哪个?
  • 使我的项目变慢。 toString() 更快。
【解决方案3】:

在我的测试中,Enum.GetName 速度更快,而且幅度也不错。在内部ToString 调用Enum.GetNameFrom source .NET 4.0,要点:

public override String ToString()
{
     return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
}

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
    {
        String retval = GetName(eT, value); //<== the one
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else
    {
        return InternalFlagsFormat(eT, value);
    }
}

我不能说这是肯定的原因,但测试状态一个比另一个更快。这两个调用都涉及装箱(实际上它们是反射调用,您实际上是在检索字段名称)并且可能会根据您的喜好缓慢。

测试设置:有 8 个值的枚举,没有。迭代次数 = 1000000

结果:Enum.GetName => 700 毫秒,ToString => 2000 毫秒

如果速度不明显,我不会在意并使用ToString,因为它提供了更清晰的通话。对比

Enum.GetName(typeof(Bla), value)

value.ToString()

【讨论】:

    【解决方案4】:

    Enum.GetName(...)

    这是最优雅的方法。

    var enumValueString = Enum.GetName(typeof (MyEnum), MyEnum.MyValue);
    

    虽然我没有看到调用 .ToString() 的任何问题,因为它更短。

    var enumValueString = MyEnum.MyValue.ToString();
    

    您可以使用新的 C# 6 语法:

    nameof(MyEnum.MyValue)
    

    【讨论】:

      【解决方案5】:

      所有这些在内部最终都会调用一个名为InternalGetValueAsString 的方法。 ToStringGetName 之间的区别在于 GetName 必须先验证几件事:

      1. 您输入的类型不为空。
      2. 您输入的类型实际上是一个枚举。
      3. 您传入的值不为空。
      4. 您传入的值是枚举可以实际用作其基础类型的类型,或者是枚举本身的类型。它在值上使用GetType 来检查这一点。

      .ToString 不必担心上述任何问题,因为它是在类本身的实例上调用的,而不是在传入的版本上,因此,由于.ToString方法没有与静态方法相同的验证问题,我认为.ToString 是获取字符串值的最快方法。

      【讨论】:

      • 你在哪里查到的这些?什么是汇编版本?我得到了非常不同的结果。
      【解决方案6】:

      我能找到的最好的是this unrelated question on MSDN,它包含一个回答这个问题的 XML sn-p。这些方法中的任何一个都有相同的缺陷:它们调用enum.toString(),在使用Dotfuscation 时无法正常工作。其他问题似乎与间接装箱(GetName 和 Format)有关。不幸的是,我找不到使用上述任何方法的任何性能原因。

      转述自xml snippet

      将装箱的枚举传递给 string.Format() 或任何其他函数可能会导致调用 enum.ToString()。 这会在 Dotfuscating 时引起问题。您不应使用enum.ToString()enum.GetNames()enum.GetName()enum.Format()enum.Parse() 将枚举转换为字符串。相反,请使用 switch 语句,并在必要时将名称国际化。

      【讨论】:

        【解决方案7】:

        Enum.GetName()

        Format() 实际上只是对GetName() 的封装,带有一些格式化功能(或者准确地说是InternalGetValueAsString())。 ToString()Format() 几乎相同。我认为GetName() 是最好的选择,因为它对任何阅读源代码的人来说都是显而易见的。

        【讨论】:

          【解决方案8】:

          我创建了一个“描述”扩展方法并将其附加到枚举,以便我可以获得真正用户友好的命名,包括空格和大小写。我从来不喜欢将枚举值本身用作可显示的文本,因为我们开发人员使用它来创建更具可读性的代码。它不适用于 UI 显示目的。我希望能够更改 UI 而无需遍历和更改枚举。

          【讨论】:

            【解决方案9】:

            我不知道“首选”方法是什么(询问 100 个人并获得 100 种不同的意见),但做最简单且有效的方法。 GetName 有效,但需要更多的击键。 ToString() 似乎做得很好。

            【讨论】:

              【解决方案10】:

              对于 VB 爱好者:

              EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
              

              【讨论】:

                【解决方案11】:

                这也可以。

                    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
                

                【讨论】:

                  【解决方案12】:

                  对我来说,将 Enum 转换为 String 的最简单方法是:

                  // Sample for Enum.ToString(String)
                  using System;
                  
                  class Sample
                  {
                      enum Colors {Red, Yellow = 12};
                  
                      public static void Main()
                      {
                      Colors myColor = Colors.Yellow;
                  
                      Console.WriteLine("Colors.Red = {0}", Colors.Red.ToString("d"));
                      Console.WriteLine("Colors.Yellow = {0}", Colors.Yellow.ToString("d"));
                  
                      Console.WriteLine("{0}myColor = Colors.Yellow{0}", Environment.NewLine);
                  
                      Console.WriteLine("myColor.ToString(\"g\") = {0}", myColor.ToString("g"));
                      Console.WriteLine("myColor.ToString(\"G\") = {0}", myColor.ToString("G"));
                  
                      Console.WriteLine("myColor.ToString(\"x\") = {0}", myColor.ToString("x"));
                      Console.WriteLine("myColor.ToString(\"X\") = {0}", myColor.ToString("X"));
                  
                      Console.WriteLine("myColor.ToString(\"d\") = {0}", myColor.ToString("d"));
                      Console.WriteLine("myColor.ToString(\"D\") = {0}", myColor.ToString("D"));
                  
                      Console.WriteLine("myColor.ToString(\"f\") = {0}", myColor.ToString("f"));
                      Console.WriteLine("myColor.ToString(\"F\") = {0}", myColor.ToString("F"));
                      }
                  }
                  /*
                  This example produces the following results:
                  Colors.Red = 0
                  Colors.Yellow = 12
                  
                  myColor = Colors.Yellow
                  
                  myColor.ToString("g") = Yellow
                  myColor.ToString("G") = Yellow
                  myColor.ToString("x") = 0000000C
                  myColor.ToString("X") = 0000000C
                  myColor.ToString("d") = 12
                  myColor.ToString("D") = 12
                  myColor.ToString("f") = Yellow
                  myColor.ToString("F") = Yellow
                  */ 
                  

                  现在要将所选字符串转换回 Enum,您只需 Parse 它:

                  var myYellowEnum = Enum.Parse(typeof (Colors), "Yellow"); // Returns Yellow
                  

                  【讨论】:

                    【解决方案13】:

                    有了新的 Roslyn 警告,这个问题让我开始思考。我的研究使我找到了 2 个图书馆。两者都显示出比内置 .NET 5 方法 ToString、GetName 等更好的性能。看看基准测试:

                    Enums.NET

                    FastEnum

                    【讨论】:

                      【解决方案14】:

                      ToString() 从可读性的角度给出了最明显的结果,而使用Enum.GetName() 需要更多的心理分析才能快速理解它试图做什么(除非你看到所有的模式时间)。

                      从纯粹的性能角度来看,正如@nawfal 的回答中已经提供的那样,Enum.GetName() 更好。

                      如果性能确实是您的目标,那么最好提前提供查找(使用字典或其他映射)。

                      在 C++/CLI 中,这看起来像

                      Dictionary<String^, MyEnum> mapping;
                      for each (MyEnum field in Enum::GetValues(MyEnum::typeid))
                      {
                          mapping.Add(Enum::GetName(MyEnum::typeid), field);
                      }
                      

                      使用 100 个项目和 1000000 次迭代的枚举进行比较:

                      Enum.GetName:~800ms
                      .ToString(): ~1600ms
                      字典映射:~250ms

                      【讨论】:

                        【解决方案15】:

                        简单:将名称枚举到列表中:

                        List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()
                        

                        【讨论】:

                        • 嗨@Brian,我认为您不需要转换 GetNames() 的输出
                        猜你喜欢
                        • 1970-01-01
                        • 2014-03-18
                        • 2015-06-10
                        • 1970-01-01
                        • 2012-08-25
                        • 1970-01-01
                        • 2016-07-30
                        • 2012-12-07
                        相关资源
                        最近更新 更多