【问题标题】:Enum methods vs string methods枚举方法与字符串方法
【发布时间】:2026-02-06 14:05:02
【问题描述】:

在性能方面,使用枚举而不是字符串数组是否更有效?

我决定测试一个特定的方法 IsDefined,而不是检查字符串数组中的匹配。我创建了一个 Stopwatch 对象来测试每个对象的运行时间。
代码如下:

在 Main 类之外定义了一个枚举:

 enum Color : byte { red, blue, green }

内部主要:

string[] colArr = new string[] { "red", "blue", "green" };
string input = "green";
Stopwatch s1 = new Stopwatch();
int loopIterations = 0;

s1.Restart();
while (loopIterations++ < 100000000)
    foreach (var blah in colArr)
        if (blah == input)
            break;
s1.Stop();
Console.WriteLine("Runtime for foreach loop: {0}", s1.Elapsed);

loopIterations = 0;
s1.Restart();
while (loopIterations++ < 100000000)
    if (Enum.IsDefined(typeof(Color), input))
        continue;
s1.Stop();
Console.WriteLine("Runtime for IsDefined method returned value: {0}", s1.Elapsed);

我的输出如下所示:

Runtime for foreach loop: 00:00:01.4862817
Runtime for IsDefined method returned value: 00:00:09.3421654
Press any key to continue . . .

所以我想问一下——假设我写的代码不是愚蠢的或什么——这些数字是正常的,如果它们是正常的,那么使用枚举比使用字符串数组更可取的方式是什么,特别是对于什么样的工作都可以?

【问题讨论】:

  • 两者都有自己的目的。您将枚举用于开发人员友好的 API,并将字符串用于用户输入。您的研究表明了什么?
  • 您正在使用像字符串一样的枚举,当然效率较低。而是将其存储为Color,例如:Color input = Color.green;。那么你就不需要检查它是否存在了。
  • Enum.IsDefined(typeof(Color), input) 的调用可能会伪造您的计算,因为它需要解析字符串并进行一些拆箱。您可以使用 Enum.GetValues 等同于 foreach(var blah in colArr) 以获得更合适的结果。
  • @TimSchmelter 我之前没有澄清这一点,但这是如何工作的,要求用户输入颜色,然后程序检查该颜色是否存在。我决定跳过输入部分,而是将字符串“green”放在输入中。所以输入类型是字符串是不可避免的,我不能将它存储在颜色中,而不先检查它是否存在,因此调用 IsDefined。
  • @ChenLeikehmacher:两件事:1)为用户提供一个下拉列表或ColorDialog。然后你不需要检查它是否存在。 2)你问错了问题。用户只给你一个输入,你正在测量 100000000 Enum.IsDefined 呼叫。在这种情况下,性能是您最不应该关心的事情。

标签: c# arrays enums


【解决方案1】:

对于初学者来说,使用枚举而不是字符串的一个重要原因是代码的可维护性,而不是性能。例如,在 Visual Studio 中单击几下即可尝试“查找所有对 Color.red 的引用”。试图找到字符串并不容易。总是键入字符串也容易出错。虽然这两个问题都可以通过使用常量来缓解,但使用枚举更容易。

枚举可以看成是一个常量整数值,它具有良好的性能,并且具有使用标志(掩码)等好处。比较一个 int 比比较一个字符串要快,但这不是这里发生的事情。大多数情况下,您想为特定值做某事,您可以测试 if(someString == "red")if(someColVal == Color.red),在这种情况下,后者应该更快。

使用Enum.IsDefined 检查枚举中是否存在值可能会更慢,但该函数每次都必须在此循环中查找枚举值。 同时第一个测试有一个预定义的数组。为了与您的第一次测试进行严格的性能比较,您可以执行以下操作:

var colvalues = Enum.GetValues(typeof(Color)).Cast<Color>().ToArray();  // or hardcode: var colvalues = new[]{Color.red, Color.blue, Color.green};
var colinput = Color.red;
while (loopIterations++ < 100000000)
    foreach (var blah in colvalues)
        if (blah == colinput)
            break;

尽管如上所述,查找 enum 中是否存在值通常不是其主要功能(主要用于检查特定值)。但是它的整数基数允许其他方法检查值是否在预期范围内,例如掩码检查或&gt;&gt;=&lt;&lt;=

edit 查看有关用户输入的 cmets:主要是输入将被控制,例如:向用户显示一个菜单。在控制台环境中,可以使用枚举的数字构建菜单。 例如枚举enum Color : byte { red = 1, blue, green },菜单 1.红色 2. 蓝色 3.绿色

用户输入将是一个整数。另一方面,如果需要输入,IsDefined 将避免重新输入值并且便于使用。出于性能考虑,名称可以使用 var colvalues = Enum.GetNames(typeof(Color)).ToArray();

之类的内容进行缓冲

【讨论】:

  • 姓名:TBH,我不会说使用面具是一种好处。恕我直言,维护起来并不容易,并且会导致更多的代码混乱和错误,而不是任何所谓的好处。这在内存受限的 1990 年代可能是有道理的,但在当今世界,我们最好将“选定的”枚举保存到集合中。
  • @code4life 就我个人而言,我喜欢带有掩码的标志枚举。 (对于作为颜色的单个值,它们当然是无用的)。不是因为内存限制,而是您可以轻松添加或删除值。例如一个边框枚举属性:someClass.Border |= Border.Left 设置左边框,无论它是否已经设置。如果您对集合执行此操作,则可能会获得无限条目,除非您添加额外的代码来检查该值是否已经在集合中
【解决方案2】:

枚举的正常用途是表示逻辑状态或有限范围的选项:在您的示例中,如果例如一种产品只有三种​​颜色。在这种情况下使用字符串表示颜色有两个缺点:您可能会在代码中的某处拼错颜色名称,并且难以跟踪错误;并且字符串比较本质上比比较枚举慢(基本上是比较整数)。

IsDefined() 使用类型反射,因此应该比直接字符串比较慢。在某些情况下,您希望将枚举与字符串进行转换:通常是在进行输入/输出时,例如保存或恢复配置。这速度较慢,但​​输入/输出通常由存储介质和网络的慢速支配,因此很少有什么大不了的。

【讨论】:

  • 我知道这没什么大不了的,但关键是使用字符串的输入操作会产生更好的(如果无关紧要的话)性能提升。正如我在问题的 cmets 中所写,要求用户输入颜色的名称,然后程序会寻找匹配项。对于这些类型的作业,最好使用字符串数组。
  • @Chen 您可以将字符串转换为枚举 once 然后使用 IsDefined。这就是 IsDefined 在内部所做的。它将字符串转换为枚举一次,然后开始比较。当您将其放入循环中时,转换也包含在循环中。所以你的基准是错误的。因为您正在测量将字符串转换为枚举的开销。
  • 对于这些类型的作业,最好使用字符串数组 不,代码可读性和性能之间存在权衡。使用字符串数组,您会降低代码的可维护性和可读性,而不会带来合理的性能提升。 @陈
【解决方案3】:

我知道这是一篇非常古老的帖子,但注意到循环的比较代码 sn-ps 并没有以类似的方式进行循环。 与第一个循环一样,一旦在字符串数组中找到字符串,就让循环中断,但在第二种情况下,如果 Enum.IsDefined 找到值,则不要让循环停止而是继续。

当你真正让枚举场景中的循环在找到值时中断时,枚举场景运行得更快......

【讨论】: