C#中字符串比较方法的区别
Posted
技术标签:
【中文标题】C#中字符串比较方法的区别【英文标题】:Differences in string compare methods in C# 【发布时间】:2010-09-07 20:11:17 【问题描述】:在 C# 中比较字符串非常简单。事实上,有几种方法可以做到这一点。我在下面的块中列出了一些。我很好奇的是它们之间的区别以及何时应该使用其他的?是否应该不惜一切代价避免?还有更多我没有列出的吗?
string testString = "Test";
string anotherString = "Another";
if (testString.CompareTo(anotherString) == 0)
if (testString.Equals(anotherString))
if (testString == anotherString)
(注意:我在这个例子中寻找平等,不小于或大于,但也可以随意评论)
【问题讨论】:
一个陷阱是你不能做 stringValue.Equals(null) 因为假设你可以在 null 上调用一个方法 MSDN Reference @RobertHarvey 我来 *** 的原因是我不必阅读多页的答案。 @Syaiful:我来 Stack Overflow 的原因是为了找到文档中没有的答案。 【参考方案1】:以下是这些函数如何工作的规则:
stringValue.CompareTo(otherStringValue)
null
出现在字符串之前
它使用CultureInfo.CurrentCulture.CompareInfo.Compare
,这意味着它将使用文化相关的比较。这可能意味着ß
将与德国的SS
比较,或类似
stringValue.Equals(otherStringValue)
null
不等于任何东西
除非您指定 StringComparison
选项,否则它将使用看起来像直接序号相等检查的内容,即 ß
与 SS
不同,在任何语言或文化中
stringValue == otherStringValue
-
与
stringValue.Equals()
不同。
==
运算符调用静态Equals(string a, string b)
方法(该方法又转到内部EqualsHelper
进行比较。
在null
字符串上调用.Equals()
会得到null
引用异常,而在==
上不会。
Object.ReferenceEquals(stringValue, otherStringValue)
只需检查引用是否相同,即它不仅仅是两个具有相同内容的字符串,而是将一个字符串对象与其自身进行比较。
请注意,对于使用方法调用的上述选项,存在带有更多选项的重载来指定如何进行比较。
如果您只想检查是否相等,我的建议是决定是否要使用与文化相关的比较,然后根据选择使用.CompareTo
或.Equals
。
【讨论】:
"stringValue.Equals(otherStringValue): null 不等于 null" 大声笑,我会说不。 null 等于 ObjectReferenceNotSet 异常。 == 与 .Equals() 不同... == 运算符调用静态 Equals(string a, string b) 方法(该方法又转到内部 EqualsHelper 执行比较。在空字符串上调用 .Equals 会得到空引用 exc.,而在 == 上则不会。 另一方面,.Equals 稍微快一些(内部方法调用少),但可读性较差 - 当然可以说:)。 我在想 '==' 会进行引用比较,而 object.equals 会进行值比较。'==' 和 string.equals 的工作方式是一样的吗? 应该在答案中指出==差异,这是一个很大的差异。【参考方案2】:来自 MSDN:
“CompareTo 方法主要设计用于排序或 字母顺序操作。不应该在初级时使用 方法调用的目的是判断两个字符串是否 相等的。要确定两个字符串是否等价,请调用 Equals 方法。”
他们建议在仅寻找平等时使用.Equals
而不是.CompareTo
。我不确定 .Equals
和 ==
对于 string
类之间是否有区别。我有时会在我自己的类中使用.Equals
或Object.ReferenceEquals
而不是==
,以防有人稍后出现并为该类重新定义==
运算符。
【讨论】:
你遇到过这种情况吗? (重新定义 == )...我认为它太防御性编程 =) 是的,这就是为什么我现在在寻找对象相等性时使用 Object.ReferenceEquals :)。这可能有点过度防御,但我并不对此感到疯狂,而且说实话这种情况不会经常出现。 我怀疑这种“防御性编码”是否有用。如果类所有者需要重写 == 运算符,然后发现没有人使用它怎么办? @DaveVandenEynde:是的......我前一阵子写了这个。我不经常这样做,只在适当的时候覆盖 .Equals。 微软的推荐记录在这里:Best Practices for Using Strings in the .NET Framework【参考方案3】:如果您对 BCL 方法的差异感到好奇,Reflector 是您的朋友 :-)
我遵循以下准则:
完全匹配: 编辑:我以前总是使用 == 运算符,其原理是在 Equals(string, string) 内部,对象 == 运算符用于比较对象引用,但它似乎 strA.Equals(strB) 总体上仍然比 string.Equals(strA, strB)、strA == strB 和 string.CompareOrdinal(strA, strB) 快 1-11%。我使用 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
【讨论】:
【参考方案4】:正如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;
【讨论】:
区分大小写怎么样? 并备注您可以使用string.Equals(a, b)
【参考方案5】:
关于字符串比较问题的良好解释和实践可以在文章New Recommendations for Using Strings in Microsoft .NET 2.0 和Best Practices for Using Strings in the .NET Framework 中找到。
每个提到的方法(和其他)都有特定的目的。它们之间的主要区别在于它们默认使用的是哪种StringComparison Enumeration。有几种选择:
当前文化 CurrentCultureIgnoreCase 不变文化 InvariantCultureIgnoreCase 序数 OrdinalIgnoreCase上述每种比较类型针对不同的用例:
序数 区分大小写的内部标识符 XML 和 HTTP 等标准中区分大小写的标识符 区分大小写的安全相关设置 OrdinalIgnoreCase 不区分大小写的内部标识符 XML 和 HTTP 等标准中不区分大小写的标识符 文件路径(在 Microsoft Windows 上) 注册表键/值 环境变量 资源标识符(例如句柄名称) 不区分大小写的安全相关设置 InvariantCulture 或 InvariantCultureIgnoreCase 一些持久的语言相关数据 显示需要固定排序顺序的语言数据 CurrentCulture 或 CurrentCultureIgnoreCase 向用户显示的数据 大多数用户输入请注意,StringComparison Enumeration 以及字符串比较方法的重载自 .NET 2.0 起就存在。
String.CompareTo Method (String)
实际上是IComparable.CompareTo Method 的类型安全实现。默认解释:CurrentCulture。
用法:
CompareTo 方法主要用于排序或字母排序操作
这样
实现IComparable接口必然会用到这个方法
String.Compare Method
String Class 的一个静态成员,它有很多重载。默认解释:CurrentCulture。
只要有可能,您应该调用包含 StringComparison 参数的 Compare 方法的重载。
String.Equals Method
从 Object 类重写并为类型安全而重载。默认解释:序数。 请注意:
String 类的相等方法包括 static Equals、静态运算符 == 和 实例方法 Equals。
StringComparer class
还有另一种处理字符串比较的方法,特别是针对排序:
您可以使用StringComparer class 创建特定于类型的比较来对通用集合中的元素进行排序。 Hashtable、Dictionary、SortedList 和 SortedList 等类使用 StringComparer 类进行排序。
【讨论】:
根据 SO 上的一些其他帖子,除了序数方法之外的所有方法都有比较(a,b)和比较(b,a)都可以返回 1 的情况,并且该错误已归类为“不会被修复”。因此,我不确定任何此类比较是否有任何用例。 @supercat 你能链接到那个,或者举个例子吗? 请参阅***.com/questions/17599084/… 了解有关该问题的讨论。【参考方案6】:在 99% 的情况下,性能通常并不重要,但如果您必须在循环中执行数百万次,我强烈建议您使用 .Equals 或 ==,因为只要它找到一个不匹配的字符会将整个事情作为假抛出,但如果你使用 CompareTo 它将不得不找出哪个字符小于另一个,导致性能时间稍差。
如果您的应用将在不同的国家/地区运行,我建议您查看 CultureInfo 的含义并可能使用 .Equals。因为我只真正为美国编写应用程序(并且不在乎是否有人无法正常工作),所以我总是只使用 ==。
【讨论】:
【参考方案7】:在您在此处列出的表格中,两者之间没有太大区别。 CompareTo
最终调用了一个 CompareInfo
方法,该方法使用当前文化进行比较; Equals
由 ==
运算符调用。
如果您考虑重载,那么情况会有所不同。 Compare
和 ==
只能使用当前区域性来比较字符串。 Equals
和 String.Compare
可以采用 StringComparison
枚举参数,让您指定不区分区域性或不区分大小写的比较。只有 String.Compare
允许您指定 CultureInfo
并使用默认区域性以外的区域性执行比较。
由于它的多功能性,我发现我使用String.Compare
比任何其他比较方法都多;它让我可以准确地指定我想要的。
【讨论】:
【参考方案8】:需要注意的一个很大区别是,如果第一个字符串为空,.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");
【讨论】:
【参考方案9】: s1.CompareTo(s2):如果主要目的是确定两个字符串是否相等,则不要使用 s1 == s2:不能忽略大小写 s1.Equals(s2, StringComparison): 如果 s1 为 null,则抛出 NullReferenceException String.Equals(s2, StringComparison):通过消除的过程,这个static方法就是WINNER(假设一个典型的用例来判断是否两个字符串是等价的)!【讨论】:
【参考方案10】:使用 .Equals 也更容易阅读。
【讨论】:
【参考方案11】:使用 .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。但是,这是区分大小写的,我认为 CompareTo 可能有一些选项可以忽略大小写等,但现在没有时间看。 正如其他人已经说过的那样,这将用于排序。以这种方式比较相等会导致不必要的开销。
我确定我会遗漏一些内容,但如果您需要更多详细信息,我认为这应该足以开始试验。
【讨论】:
a==b 部分不正确。 == 运算符为 String 类有效地重载,它比较值而不考虑实际引用。以上是关于C#中字符串比较方法的区别的主要内容,如果未能解决你的问题,请参考以下文章
C#中String的静态方法Compare(str1,str2)比较字符串大小