Enum.Parse()vs开关性能

时间:2014-10-31 15:28:32

标签: c# performance

一切都在标题中,我已经阅读了这个问题Enum.Parse() or Switch但是没有关于表现的内容。我的Enum大约有10个成员,我想知道哪个更快,切换或Enum.Parse()?

6 个答案:

答案 0 :(得分:8)

切换总是更快,因为parse使用反射来获取成员的名称..但除非应用程序性能至关重要......(每秒数千次执行)..使用Enum.Parse使代码更易于维护

答案 1 :(得分:7)

美好而快速:

public static class EnumHelpers<TTarget>
{
    static EnumHelpers()
    {
        Dict = Enum.GetNames(typeof(TTarget)).ToDictionary(x => x, x => (TTarget)Enum.Parse(typeof(TTarget), x), StringComparer.OrdinalIgnoreCase);
    }

    private static readonly Dictionary<string, TTarget> Dict;

    public static TTarget Convert(string value)
    {
        return Dict[value];
    }
}

答案 2 :(得分:4)

我使用表达式树构建了一个快速的“切换”版本。

public static Func<String, TEnum> GetParseEnumDelegate<TEnum>()
{
  var eValue = Expression.Parameter(typeof(String), "value"); // (String value)
  var tEnum = typeof(TEnum);

  return
    Expression.Lambda<Func<String, TEnum>>(
      Expression.Block(tEnum,
        Expression.Switch(tEnum, eValue,
          Expression.Block(tEnum,
            Expression.Throw(Expression.New(typeof(Exception).GetConstructor(Type.EmptyTypes))),
            Expression.Default(tEnum)
          ),
          null,
          Enum.GetValues(tEnum).Cast<Object>().Select(v => Expression.SwitchCase(
            Expression.Constant(v),
            Expression.Constant(v.ToString())
          )).ToArray()
        )
      ), eValue
    ).Compile();
}
...
var parseEnum = GetParseEnumDelegate<YourEnum>();
YourEnum e = parseEnum("SomeEnumValue");

如果您需要非通用版本,则必须将交换机的结果从tEnum转换为typeof(Object)。

public static Func<String, Object> GetParseEnumDelegate(Type tEnum)
{
  var eValue = Expression.Parameter(typeof(String), "value"); // (String value)
  var tReturn = typeof(Object);

  return
    Expression.Lambda<Func<String, Object>>(
      Expression.Block(tReturn,
        Expression.Convert( // We need to box the result (tEnum -> Object)
          Expression.Switch(tEnum, eValue,
            Expression.Block(tEnum,
              Expression.Throw(Expression.New(typeof(Exception).GetConstructor(Type.EmptyTypes))),
              Expression.Default(tEnum)
            ),
            null,
            Enum.GetValues(tEnum).Cast<Object>().Select(v => Expression.SwitchCase(
              Expression.Constant(v),
              Expression.Constant(v.ToString())
            )).ToArray()
          ), tReturn
        )
      ), eValue
    ).Compile();
}

我做了几次性能测试,这个委托版本几乎和本机开关一样快。在我的场景中(包含10个项目的枚举),它比Enum.Parse()快5倍。

答案 3 :(得分:1)

正如@CaldasGSM回答的那样,最大的问题是Enum.Parse方法内部正在发生的反思。此外,Enum.Parse内部实现中使用的IF的数量远远高于switch语句中的条件数,而不是计算该方法中的其他代码。所有这些都使它不如switch

如果您正在处理像您所说的少量项目,那么如果您使用的是Enum.Parse vs switch,则实际上没有显着差异。对于大量的项目来说,这是一个不同的故事。

但是,我要补充一点,Enum.Parse的另一个问题是,在解析不起作用的情况下,你必须使用try-catch块处理三种异常类型,这也会减慢代码的速度。

此外,在使用Enum.Parse时,您也不应忽略在object类型中装入枚举值的成本,这也是性能损失。

要解决上述问题,更好的选择是使用较新的Enum.TryParse API,这样可以更轻松地处理错误,并且还可以阻止装箱对象,因为它使用泛型。

以下是一个例子:

Items item;
if (!Enum.TryParse("First", true, out item))
{
    // Handle error
}

答案 4 :(得分:1)

孤立地,switch会更快。

但代码很少孤立地执行。通常,用户将输入一个值,或者您将从磁盘文件中加载它。 Enum的全部目的是对字符串值进行符号表示,以便您可以更轻松地使用它。它还允许您验证输入的数据。

所以,让我们说你有一个枚举:

public enum Thing
{
    Foo,
    Bar,
    Fooby,
    Barby
}

有人给你一个字符串,应该代表其中一个。你写了一个switch语句:

switch (s)
{
    case "Foo": break;
    case "Bar": break;
    case "Fooby": break;
    case "Barby": break;
    default : throw new ArgumentException();
}

如果用户输入&#34; foo&#34;会发生什么?你是否会拒绝它,因为案件不正确?非常不友好的行为。因此,您修改代码以对字符串执行ToLower(),并修改您的案例以使用全部小写。

太疯狂了。如果使用Enum.TryParse将其转换为枚举,则可以更容易理解和维护代码,然后使用枚举值执行需要完成的操作。

答案 5 :(得分:0)

使用开关(我更喜欢使用解析,因为它更易于维护)。

无论如何,过早优化是万恶之源。