Enum.Parse()或Switch

时间:2011-09-21 08:58:59

标签: c# performance parsing enums switch-statement

要将字符串转换为枚举,以下哪种方式更好?

  1. 此代码:

    colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green");
    
  2. 或者:

    string colorString = ...
    colorEnum color;        
    switch (colorString)
    {
        case "Green":
            color = colorEnum.Green;
            break;
        case "Red":
            color = colorEnum.Red;
            break;
        case "Orange":
            color = colorEnum.Orange;
            break;
        ....
    }
    

11 个答案:

答案 0 :(得分:8)

您应该使用Enum.TryParse,如果失败,您可以正确处理错误。

样品:

     ColorsEnum colorValue; 
     if (Enum.TryParse(colorString, out colorValue))        
        if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))  
           Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
        else
           Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
     else
        Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString);

答案 1 :(得分:7)

(警告:包含我自己的开源库的插件......)

就个人而言,我会使用Unconstrained Melody,最终会使用更清晰,更安全的代码:

ColorEnum color = Enums.ParseName<ColorEnum>(text);

如果您怀疑它可能无效,可以使用TryParseName。显然这需要一个额外的库,但希望你也能找到其他有用的东西:)

.NET 4中的

Enum.TryParse比其他内置选项更好,但是:

  • 您不会在编译时捕获非枚举类型,例如Enum.TryParse<int>(...)仍将编译;无约束的旋律真的只允许枚举类型
  • Enum.TryParse也将解析“1”(或转换为字符串时的数值) - 如果你真的只是期望的名字,我认为最好只用接受名称

我绝对不会切换字符串值 - 这意味着如果重命名枚举值,您必须记住重命名案例值。

答案 2 :(得分:4)

那么Enum.TryParse<TEnum>呢?

string myColorStr = "red";
colorEnum myColor;
if(!Enum.TryParse<colorEnum>(myColorStr, true, out myColor))
{
    throw new InvalidOperationException("Unknown color " + myColorStr);
}

答案 3 :(得分:2)

1)好多了。这是更清洁的代码。你在一行中做了多少2)。此外,它不容易出错。当你向colorEnum添加另一个项目时,你需要记住扩展2)wheras 1)才能正常工作。

您可能还需要对Enum.Parse进行错误处理。

答案 4 :(得分:2)

仅限于可读性和可维护性。如果你扩展枚举,你不需要做额外的工作,有2个你需要在switch语句中添加更多的情况

答案 5 :(得分:2)

因为你添加了标签'performance',所以我会选择开关 是的,当您重命名/添加/删除枚举中的任何内容时,您将不得不更改案例。那太糟糕了。 Enum.Parse / TryParse的任何变体都使用了很多奇怪的代码和一些反射,只需看一下ILSpy等函数。然后还有接受“-12354”的问题,甚至是逗号分隔的有效名称列表(导致所有这些名称一起被OR化),即使枚举没有[Flags]属性。

作为替代方案,您可以创建一个将枚举名称转换为值的字典。它实际上应该比开关更快,因为字符串上的开关也会通过字典但你保存实际的开关部分。

显然,这两种方式都需要比enum.parse和变体更多的维护;是否值得它取决于,因为在我们所有人中,只有你对项目有足够的了解才能使性能/编码时间权衡。

答案 6 :(得分:1)

除了两个不同的代码片段没有做同样的事情之外,我会用这个:

colorEnum color;
if (!colorEnum.TryParse(colorString, true, out color)
    color = colorEnum.Green;    // Or whatever default value you wish to have.

如果你没有.NET 4.0,那么我会做这样的事情:

public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
    if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
        return defaultValue;

    return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}

这是Extension Methodstring

答案 7 :(得分:1)

就个人而言,虽然我对非性能场景的Enum.Parse解决方案完全没问题(阅读:偶尔运行此功能一次......并且有很多这样的场景可以肯定),我无法忍受当这个函数需要一次在数百/千多个枚举值的循环中执行时,可能涉及一些反射类型方法的想法。 GACK!

所以以下是一个解决方案,可以获得两个世界中最好的一些。

只需在启动时检索枚举的所有值,或者什么不是,只要它最适合您(下面是一种方法),然后用它们构造一个词典。

    private static Dictionary<string, Color> colorDictionary;
    public static Dictionary<string, Color> ColorDictionary
    {
        get
        {
            if (colorDictionary== null) {
                colorDictionary = new Dictionary<string, Color>();
                var all = Enum.GetValues(typeof(Color)).OfType<Color>();
                foreach (var val in all)
                    dict.Add(val.ToString(), val);
            }
            return colorDictionary;
        }
    }

答案 8 :(得分:0)

我发现开关变体很糟糕,因为每次更改枚举时都必须修改开关。

我喜欢使用属于你的枚举的TryParse。所以你可以像这样使用它

string colorString = .....
colorEnum color;

colorEnum.TryParse(colorString, out color);

或者如果你不关心字符串的情况

colorEnum.TryParse(colorString, true, out color);

如果字符串是有效的枚举,则TryParse的返回值为true,否则为false。

答案 9 :(得分:0)

从性能的角度来看,由于枚举是作为静态字段实现的,因此parse方法可能最终会对枚举类型进行反射,并尝试一种可能比这种情况更快的GetField方法。另一方面,如果90%的情况,颜色为绿色,则情况会非常快......请注意,CLR有时会在内部重新排列代码,根据统计信息更改案例的顺序(实际上,我是不确定它是否那样,但文件声称它可以)。

答案 10 :(得分:0)

我使用以下内容,它可以为您提供所有类型的安全性,同时在向Enum添加新值时仍然不会失败,它也非常快。

public static colorEnum? GetColorFromString(string colorString)
{
    colorEnum? retVal = null;
    if(Enum.IsDefined(typeof(colorEnum), colorString))
        retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString);
    return retVal;
}

我在枚举中使用8个项目的测试显示这种方式比切换方法更快。

否则你可以使用(非常慢的方式):

public static colorEnum? GetColorFromString(string colorString)
{
    foreach (colorEnum col in Enum.GetValues(typeof(colorEnum)))
    {
        if (col.ToString().Equals(colorString))
        {
            return col;
        }
    }
    return null;
}