280

在 C# 中比较字符串非常简单。事实上,有几种方法可以做到这一点。我在下面的块中列出了一些。我很好奇的是它们之间的区别以及何时应该使用它们而不是其他的?是否应该不惜一切代价避免?还有更多我没有列出的吗?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(注意:我在这个例子中寻找平等,不小于或大于,但也可以随意评论)

4

11 回答 11

238

以下是这些函数如何工作的规则:

stringValue.CompareTo(otherStringValue)

  1. null出现在字符串之前
  2. 它使用CultureInfo.CurrentCulture.CompareInfo.Compare,这意味着它将使用与文化相关的比较。这可能意味着ß将与SS德国或类似

stringValue.Equals(otherStringValue)

  1. null不被认为等于任何东西
  2. 除非您指定一个StringComparison选项,否则它将使用看起来像直接序数相等检查的内容,即在任何语言或文化中都ß与, 不同SS

stringValue == otherStringValue

  1. 不一样stringValue.Equals()
  2. ==操作员调用静态方法(该Equals(string a, string b)方法又转到内部EqualsHelper进行比较。
  3. 调用字符串会得到引用异常,而 on.Equals()不会。nullnull==

Object.ReferenceEquals(stringValue, otherStringValue)

只需检查引用是否相同,即不只是两个具有相同内容的字符串,而是将字符串对象与其自身进行比较。


请注意,对于使用方法调用的上述选项,存在带有更多选项的重载来指定如何进行比较。

如果您只想检查是否相等,我的建议是决定是否要使用与文化相关的比较,然后根据选择使用.CompareToor 。.Equals

于 2008-09-04T18:17:00.097 回答
74

来自 MSDN:

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

他们建议在仅寻找平等时使用.Equals而不是。.CompareTo我不确定班级之间.Equals和班级之间==是否有区别。string我有时会使用.EqualsorObject.ReferenceEquals代替==我自己的类,以防有人稍后出现并重新定义==该类的运算符。

于 2008-09-04T17:49:27.743 回答
50

如果您对 BCL 方法的差异感到好奇,Reflector是您的朋友 :-)

我遵循以下准则:

完全匹配: 编辑:我以前一直使用 == 运算符,其原则是在 Equals(string, string) 内部,对象 == 运算符用于比较对象引用,但似乎 strA.Equals(strB) 仍然是 1-11%总体上比 string.Equals(strA, strB)、strA == strB 和 string.CompareOrdinal(strA, strB) 更快。我使用 StopWatch 对实习/非实习字符串值进行了循环测试,字符串长度相同/不同,大小不同(1B 到 5MB)。

strA.Equals(strB)

人类可读的匹配(西方文化,不区分大小写):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

人类可读的匹配(CultureInfo 定义的所有其他文化、不区分大小写/重音/假名/等):

string.Compare(strA, strB, myCultureInfo) == 0

与自定义规则的人类可读匹配(所有其他文化):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
于 2009-02-04T20:10:16.237 回答
18

正如Ed所说,CompareTo 用于排序。

但是,.Equals 和 == 之间是有区别的。

==基本上解析为以下代码:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

原因很简单,下面会抛出异常:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

以下不会:

string a = null;
string b = "foo";

bool equal = a == b;
于 2009-02-04T20:18:47.997 回答
15

在 Microsoft .NET 2.0 中使用字符串的新建议以及在 .NET Framework 中使用字符串的最佳实践中可以找到关于字符串比较问题的良好解释和实践。


每个提到的方法(和其他)都有特定的目的。它们之间的主要区别在于它们默认使用的StringComparison Enumeration类型。有几种选择:

  • 当前文化
  • 当前文化忽略案例
  • 不变文化
  • 不变文化忽略大小写
  • 序数
  • 序数忽略大小写

上述每种比较类型都针对不同的用例:

  • 序数
    • 区分大小写的内部标识符
    • XML 和 HTTP 等标准中区分大小写的标识符
    • 区分大小写的安全相关设置
  • 序数忽略大小写
    • 不区分大小写的内部标识符
    • XML 和 HTTP 等标准中不区分大小写的标识符
    • 文件路径(在 Microsoft Windows 上)
    • 注册表项/值
    • 环境变量
    • 资源标识符(例如句柄名称)
    • 不区分大小写的安全相关设置
  • InvariantCulture 或 InvariantCultureIgnoreCase
    • 一些持久的语言相关数据
    • 显示需要固定排序顺序的语言数据
  • CurrentCulture 或 CurrentCultureIgnoreCase
    • 向用户显示的数据
    • 大多数用户输入

请注意,StringComparison 枚举以及字符串比较方法的重载从 .NET 2.0 开始就存在。


String.CompareTo 方法(字符串)

实际上是IComparable.CompareTo Method的类型安全实现。默认解释:CurrentCulture。

用法:

CompareTo 方法主要用于排序或字母排序操作

因此

实现 IComparable 接口必然会用到这个方法

String.Compare 方法

具有许多重载的String 类的静态成员。默认解释:CurrentCulture。

只要有可能,您应该调用包含 StringComparison 参数的 Compare 方法的重载。

String.Equals 方法

从 Object 类重写并为类型安全而重载。默认解释:序数。请注意:

String 类的相等方法包括静态 Equals静态运算符 ==实例方法 Equals


字符串比较器类

还有另一种处理字符串比较的方法,特别是针对排序:

您可以使用StringComparer 类创建特定于类型的比较,以对通用集合中的元素进行排序。Hashtable、Dictionary、SortedList 和 SortedList 等类使用 StringComparer 类进行排序。

于 2013-03-07T12:31:21.327 回答
7

并不是说性能通常与您需要执行此操作的 99% 次有关,但如果您必须在循环中执行数百万次,我强烈建议您使用 .Equals 或 == 因为一旦它找到一个字符不匹配它会将整个事情抛出为假,但如果你使用 CompareTo 它将不得不找出哪个字符小于另一个,导致性能时间稍差。

如果您的应用程序将在不同的国家/地区运行,我建议您查看 CultureInfo 的含义并可能使用 .Equals。因为我只真正为美国编写应用程序(并且不在乎是否有人不能正常工作),所以我总是只使用 ==。

于 2008-09-04T18:12:04.023 回答
5

在您在此处列出的表格中,两者之间没有太大区别。 CompareTo最终调用一个CompareInfo使用当前文化进行比较的方法;Equals==操作员调用。

如果您考虑重载,那么情况会有所不同。 Compare并且==只能使用当前区域性来比较一个字符串。 Equals并且String.Compare可以采用StringComparison枚举参数,让您指定不区分区域性或不区分大小写的比较。仅String.Compare允许您指定 aCultureInfo并使用默认区域性以外的区域性执行比较。

由于它的多功能性,我发现我使用String.Compare的比任何其他比较方法都多;它让我可以准确地指定我想要的东西。

于 2008-09-04T17:50:08.757 回答
2

需要注意的一个很大的区别是 .Equals() 如果第一个字符串为空,则会抛出异常,而 == 不会。

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
于 2013-06-28T09:33:09.023 回答
1
  • s1.CompareTo(s2): 如果主要目的是确定两个字符串是否等价,则不要使用
  • s1 == s2: 不能忽略大小写
  • s1.Equals(s2, StringComparison): 如果 s1 为 null,则抛出 NullReferenceException
  • String.Equals(s2, StringComparison): 通过消除过程,这个静态方法就是WINNER(假设一个典型的用例来判断两个字符串是否等价)!
于 2017-12-14T18:32:16.513 回答
-1

使用 .Equals 也更容易阅读

于 2008-09-04T18:03:34.013 回答
-9

使用 .Equals,您还可以获得 StringComparison 选项。忽略大小写和其他事情非常方便。

顺便说一句,这将评估为假

string a = "myString";
string b = "myString";

return a==b

由于 == 比较 a 和 b 的值(它们是指针),因此只有当指针指向内存中的同一对象时,才会评估为 true。.Equals 取消引用指针并比较存储在指针处的值。a.Equals(b) 在这里是正确的。

如果您将 b 更改为:

b = "MYSTRING";

那么 a.Equals(b) 是假的,但是

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

会是真的

a.CompareTo(b) 调用字符串的 CompareTo 函数,该函数比较指针处的值,如果存储在 a 的值小于存储在 b 的值,则返回 <0,如果 a.Equals(b) 为真,则返回 0,并且>0 否则。但是,这是区分大小写的,我认为 CompareTo 可能有一些选项可以忽略大小写等,但现在没有时间看。正如其他人已经说过的那样,这将用于排序。以这种方式比较相等会导致不必要的开销。

我确定我会遗漏一些东西,但我认为如果您需要更多详细信息,这应该是足够的信息来开始试验。

于 2010-03-25T13:36:51.843 回答