C#中字符串比较的性能表现

23

有许多比较字符串的方式。采用某种方式比另一种方式更快吗?

我总是选择像这样比较字符串:

string name = "Bob Wazowski";
if (name.CompareTo("Jill Yearsley") == 0) {
    // whatever...
}

但我发现很少有人这样做,相反,我看到更多的人只是直接使用==比较,就我所知,这是比较字符串的最糟糕的方式。我错了吗?

此外,在LINQ查询中比较字符串是否有区别?例如,我喜欢这样做:

var results = from names in ctx.Names
              where names.FirstName.CompareTo("Bob Wazowski") == 0
              select names;

但是,我又发现很少有人在他们的LINQ查询中像这样进行字符串比较。


可能是Differences in string compare methods in C#的重复问题。 - crowder
你可能想查看http://rhale78.wordpress.com/2011/05/16/string-equality-and-performance-in-c/。 - nawfal
10个回答

29

根据Reflector

"Hello" == "World"

相同。
String.Equals("Hello", "World");

这段代码基本上用于确定两个对象是否为同一个引用对象,如果其中一个对象为空,则自动返回false(即使另一个对象非空),然后使用不安全的循环比较每个字符。因此,它完全不考虑文化规则,通常这并不是什么大问题。

以及

"Hello".CompareTo("World") == 0

等同于

CultureInfo.CurrentCulture.CompareInfo.Compare("Hello", "World", CompareOptions.None);

这基本上是相反的功能。它将考虑字符串的文化、编码和所有其他内容并置于上下文中。

因此,我想 String.CompareTo 比等号运算符慢几个数量级

至于 LINQ,如果您使用的是 LINQ-to-SQL,则无论使用哪种方式都会生成相同的 SQL。

var results = from names in ctx.Names
          where names.FirstName.CompareTo("Bob Wazowski") == 0
          select names;
< p >的
SELECT [name fields]
FROM [Names] AS [t0]
WHERE [t0].FirstName = @p0

所以对于LINQ-to-SQL,你真的没有获得任何东西,除了更难阅读的代码和可能更多地解析表达式。如果你只是在使用标准数组的LINQ,则上述规则适用。


2
string.Equals在.NET 4.0中不执行引用相等性检查,它被重载为比较实际字符串。(虽然我不会感到惊讶,如果这总是正确的。) - Massif
据我所知,string.Equals也考虑文化。 - Stefan Steinegger
1
@Massif的回复是正确的。String.Equals()和==不会比较对象引用。为了证明这一点,可以调用Object.ReferenceEquals(x,y),其中x是硬编码字符串,y是在命令行上给出的。 - GreenRibbon
这个答案确实需要纠正。这里有一个关于equals方法的好解释 - Alexander

16

我认为,你应该始终使用最清晰的方式,也就是使用==

这可以直接理解:当 "Hello" 等于 "World" 时,执行某些操作。

if ("Hello" == "World")
    // ...

内部调用String::Equals方法,该方法专门用于比较两个字符串是否相等。(这与指针和引用无关。)

这里不太明确 - 为什么要与零比较?

if ("Hello".CompareTo("World") == 0)

.CompareTo不仅用于检查相等性(你可以使用==来做这件事),它还用于比较两个字符串。在排序中,您使用.CompareTo来确定一个字符串是否“大于”另一个字符串。您可以检查相等性,因为对于相等的字符串,它会返回零,但这不是它的主要目的。

因此,有不同的方法和接口用于检查相等性(IEquatable,operator ==)和比较(IComparable)

Linq在这里的行为与常规C#无异。


3
OP并不是在询问哪种方式是写字符串比较最清晰的。对一个人来说清晰的方式可能对另一个人来说并不清晰。 - The Beaver

8
请阅读 Jeff 的 最好的代码是没有代码foo.CompareTo(bar) == 0:可怕的视觉杂乱。占用了大量空间,但没有传达任何有趣的含义。实际上,它强调了很多无关紧要的东西,使人们分散注意力,远离真正的问题。
如果没有明确的理由使用这种更长的变体,请不要使用它。
至于性能:对于这个简单的情况,它根本不重要。如果相等运算符 == 真的比 CompareTo 执行得更差,可以向 Microsoft 提交错误报告。这是不能发生的。

5

MSDN指出,您应根据需要执行的任务使用比较函数:

CompareTo方法主要用于排序或字母排序操作。当方法调用的主要目的不是确定两个字符串是否等效时,不应使用它。要确定两个字符串是否相等,请调用Equals方法。

因此,如果与排序无关且返回值不重要,则应使用:

first.Equals(second) 或者如果比较是特定于文化的,例如在德语等语言中:

String.Equals(first, second, StringComparison.CurrentCulture)

请查看以下链接:

如何:比较字符串 (C# 编程指南)

String.CompareTo 方法 (Object)


2

最近有一个类似的问题,关于最快的字符串截取方式,但基本上是在对比它们的不同方法。

你可以查看这篇帖子中的基准测试


我查看了这篇文章。谢谢,它很有用。它只是再次证实了string.length是检查字符串是否为空的最快方法,除非我误解了基准测试结果。 - Jagd

1

1

如果等号运算符的性能比CompareTo差,那么微软为什么不让等号运算符的实现调用CompareTo呢?

只需使用等号运算符来测试相等性。


1

这里是我找到的最完整和有用的MSDN字符串比较指南。

使用StringComparison.Ordinal或StringComparison.OrdinalIgnoreCase进行比较可以获得更好的性能。


0

我通常使用带有StringComparison参数的String.Compare重载,因为这样我可以绝对明确地指定比较是否区分大小写和区域性。这需要.NET 2.0或更高版本。

对于不涉及区域性的比较,最快的方法是使用StringComparison.Ordinal(如果不区分大小写,则使用StringComparison.OrdinalIgnoreCase)。

使用“==”的问题在于作者是否考虑了大小写和区域敏感性并不清楚。

这里有一篇关于此主题的好的MSDN文章here


== 是 Equals(),而 Equals() 进行大小写不敏感和区域性不敏感的搜索(最快的一种,易于记忆)。 调用 Equals(var, StringComparison.OrdinalCaseInsensetive) 比调用 Equals() 慢,因此如果要比较数百万个字符串,最好使用简单的 Equals() 而不是 == 和 2 个参数版本。 - Grigory

-2
在C#中比较字符串的最佳方法是使用a.Equals(b),其中ab是字符串。这是比较字符串的最佳方法,因为它比较对象ab的值,并且不依赖于对象的引用。
如果您要使用"=="符号,则结果将相等,如果两个对象具有相同的引用,但当它们具有不同的引用并具有相同的值时,您将遇到问题。
如果您要测试其他字符串是否在另一个字符串之前、之后或出现在同一位置,则compareTo方法是最佳方法,其中它将分别返回负值、正值或零值。如果参数是null,它还将返回正值。

1
从其他答案中已经很清楚了,但为了确保:这是错误的。字符串重载了==运算符。 - Daniel Doubleday
1
如果你要使用"=="符号,当两个对象具有相同的引用时,结果将相等,但当它们具有不同的引用并且具有相同的值时,你会遇到问题。这简直是不正确的,参见https://dev59.com/23RA5IYBdhLWcg3wzhbZ#814881。 - ViRuSTriNiTy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接