我最近被介绍给一个大型代码库,并注意到所有字符串比较都是使用
String.Equals()
而不是==
完成的。您认为这是什么原因?
#1 楼
完全有可能开发人员的很大一部分来自Java背景,使用==
比较字符串是错误的并且不起作用。在C#中,(字符串)没有(实际的)区别只要将它们键入为字符串。
如果将它们键入为
object
或T
,则请在此处查看有关泛型方法或运算符重载的其他答案,因为您肯定要使用Equals方法。 br />评论
远不及返回的值。 .quals确实提供了更多选项,但就结果而言,str1.Equals(str2)与str1 == str2相同。我确实相信他们会使用不同的方法来确定是否相等,就像布莱恩克(Blaenk)提出的乔恩·斯凯茨(Jon Skeets)所说的那样,但是它们给出了相同的值。
–马修·沙利(Matthew Scharley)
09年11月2日在2:04
@Yuriy也许您可以详细说明或提供差异链接?
–柯克·布罗德赫斯特(Kirk Broadhurst)
09年11月2日在6:57
有一个很大的不同。如果字符串之一为null,则.Equals将引发异常。
–马斯
2011年10月5日15:41
@Mas:.Equals抛出的唯一异常是null引用异常,如果您尝试在null(即)对象上调用它。字符串str1 = null; str1.Equals()。对于Equals()来说,这不是问题,任何函数都应该发生,并且不言而喻。给定相同的输入,两次比较的实际功能始终完全相同。
–马修·沙利(Matthew Scharley)
2011年10月5日在21:10
上面的链接不再起作用,但是该链接起作用了:dotnetperls.com/string-equals
– ThomasW
2012-2-22在8:36
#2 楼
string.Equals
和==
之间存在实际区别bool result = false;
object obj = "String";
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;
// Comparision between object obj and string str2 -- Com 1
result = string.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true
// Comparision between object obj and string str3 -- Com 2
result = string.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false
// Comparision between object obj and string str4 -- Com 3
result = string.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true
// Comparision between string str2 and string str3 -- Com 4
result = string.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true
// Comparision between string str2 and string str4 -- Com 5
result = string.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true
// Comparision between string str3 and string str4 -- Com 6
result = string.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true
// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false
添加手表
obj "String" {1#} object {string}
str2 "String" {1#} string
str3 "String" {5#} string
str4 "String" {1#} string
obj2 "String" {5#} object {string}
现在看看
{1#}
和{5#}
obj
,str2
,str4
和obj2
引用相同。 obj
和obj2
是object type
,其他是string type
结论:
com1:结果=(obj = = str2); // true
比较
object
和string
,因此执行引用相等性检查obj和str2指向同一个引用,因此结果为true
com2:result =(obj == str3); // false
比较
object
和string
,因此执行引用相等性检查obj和str3指向不同的引用,因此结果为false
比较
object
和string
,以便执行引用相等性检查obj和str4指向同一引用,因此结果为真
com4:结果=(str2 == str3); // true
比较
string
和string
,因此执行字符串值检查str2和str3均为“字符串”,因此结果为真
com5:结果=(str2 == str4); // true
比较
string
和string
,因此执行字符串值检查str2和str4都是“字符串”,因此结果为真
比较
string
和string
,因此执行字符串值检查str3和str4均为“字符串”,因此结果为true
com7:result =(obj = = obj2); // false
-比较
object
和object
,因此执行引用相等性检查-obj和obj2指向不同的引用,因此结果为false
评论
以上所有情况的简单说明:string.Equals(object,object)是object.Equals(object,object),它在第一个参数上调用Equals,与==运算符不同,除非重载,否则它会调用ReferenceEquals。
– Athari
13年5月21日在15:49
我相信“ String”和typeof(string).Name是不同引用的原因是前者作为编译时常量被interintered,而后者作为运行时值则不是。
–卡尔G
2013年6月25日14:07在
为什么将camelCase字符串用于Equals,而将CapCase字符串用于ReferenceEquals?
– Alex McMillan
16-9-5 '20:31
@AlexMcMillan,我可以使用字符串代替字符串,因为字符串只是System.String的别名
– vikas
16-10-14在7:19
@vikas是我的意思。.我想知道您是否有特定原因,或者只是一个不一致的原因。
– Alex McMillan
16-10-15在6:26
#3 楼
==与String.Equals方法之间有一个微妙但非常重要的区别:class Program
{
static void Main(string[] args)
{
CheckEquality("a", "a");
Console.WriteLine("----------");
CheckEquality("a", "ba".Substring(1));
}
static void CheckEquality<T>(T value1, T value2) where T : class
{
Console.WriteLine("value1: {0}", value1);
Console.WriteLine("value2: {0}", value2);
Console.WriteLine("value1 == value2: {0}", value1 == value2);
Console.WriteLine("value1.Equals(value2): {0}", value1.Equals(value2));
if (typeof(T).IsEquivalentTo(typeof(string)))
{
string string1 = (string)(object)value1;
string string2 = (string)(object)value2;
Console.WriteLine("string1 == string2: {0}", string1 == string2);
}
}
}
产生以下输出:
value1: a
value2: a
value1 == value2: True
value1.Equals(value2): True
string1 == string2: True
----------
value1: a
value2: a
value1 == value2: False
value1.Equals(value2): True
string1 == string2: True
您可以看到==运算符将false返回到两个明显相等的字符串。为什么?因为通用方法中使用的==运算符被解析为System.Object定义的op_equal方法(该方法在编译时具有T的唯一保证),这意味着它是引用相等而不是值相等。 br />
当两个值明确地键入为System.String时,==具有值相等语义,因为编译器将==解析为System.String.op_equal而不是System.Object.op_equal。
为了安全起见,我几乎总是使用String.Equals代替我总是得到我想要的值相等语义。
如果其中一个值之一,则避免NullReferenceExceptions为null,我始终使用静态String.Equals方法:
bool true = String.Equals("a", "ba".Substring(1));
评论
代码返回对象类型的东西时会发生相关的陷阱。如果var myItem = GetItem()从数据库中读取对象,则表达式“ Hi” .Equals(myItem),myItem.Equals(“ Hi”)和Object.Equals(“ Hi”,myItem)都将返回True。返回的对象是带有两个字符“ Hi”的字符串,但是myItem ==“ Hi”或“ Hi” == myItem将测试引用是否相等。在这方面,VB.NET的“ Option Strict On”方言更好。它的“ =”运算符测试要么测试值相等,要么将其编译;对于参考相等性检查,使用“ Is”运算符。
–超级猫
13年9月30日在22:53
@AndrewArnott如果我在csharppad.com上执行“ a” ==“ ab” .Substring(0,1),我将返回true。如果使用String对象,则相同。说明?
– Krumelur
15年6月24日在8:53
因为在您的示例中,编译器知道调用==运算符的System.String重载。您必须谨慎的情况是编译器不知道它是什么类型时,例如当比较的表达式键入为T或System.Object时。
–安德鲁·阿诺特(Andrew Arnott)
15年6月24日在16:12
@AndrewArnott您能否详细说明为什么.Substring()会导致不同的行为?当它返回字符串而不是包装在对象中的字符串时,为什么它的行为与第一次检查不同?对我来说,似乎两者应该具有完全相同的输出。就像在第一个示例中一样,保证在第二个示例中是字符串比较。
–Rob♦
2015年7月23日在2:02
@Rob比较是在通用方法中完成的,该方法不知道何时编译将进行字符串比较。因此,泛型方法中使用的==运算符是对象==运算符,而不是字符串==运算符。 .Substring(1)产生不同结果的原因是该方法创建了一个新的字符串对象,而不是可能重用另一个已经具有相同值的对象。因此,由于泛型方法将两个值相等但对象不同的字符串视为不同。
–安德鲁·阿诺特(Andrew Arnott)
15年7月26日在1:23
#4 楼
String.Equals
确实提供了过载功能以处理机壳和具有文化意识的比较。如果您的代码没有利用这些代码,则开发人员可能只习惯Java,而在这里(如Matthew所说),您必须使用.Equals方法进行内容比较。评论
这应该变得更高,因为文化意识(以及明确的区分大小写)的比较更加有效-例如docs.microsoft.com/zh-CN/dotnet/standard/base-types/…
– Bartosz
19年5月11日在20:01
同意@Bartosz!明确意图是Microsoft的最佳实践。使用==不会明确告诉读者在区分大小写和区域性方面会发生什么。
– Calor
20年5月4日13:19
#5 楼
两种方法在功能上都相同-它们会比较值。关于MSDN的内容:
关于
String.Equals
方法-确定此实例和另一个指定的String对象具有相同的值。 (http://msdn.microsoft.com/zh-cn/library/858x0yyx.aspx)
关于
==
-尽管字符串是引用类型,但相等运算符(==
和!=
)被定义为比较字符串对象的值,而不是引用的值。这使得测试字符串相等性更加直观。 (http://msdn.microsoft.com/zh-cn/library/362314fe.aspx)但是如果您的字符串实例之一为null,则这些方法的工作方式有所不同:
string x = null;
string y = "qq";
if (x == y) // returns false
MessageBox.Show("true");
else
MessageBox.Show("false");
if (x.Equals(y)) // returns System.NullReferenceException: Object reference not set to an instance of an object. - because x is null !!!
MessageBox.Show("true");
else
MessageBox.Show("false");
评论
请更正指向msdn.microsoft.com ** en-us ** / library /的链接,而不是en-en
–熟悉
17年7月26日在14:35
#6 楼
这篇文章有一篇文章,您可能会发现它很有趣,并引用了Jon Skeet的话。看起来用法几乎是相同的。乔恩·斯凯特(Jon Skeet)指出,“实例Equals”的性能“在字符串较短的情况下会稍好一些-随着字符串长度的增加,差异变得微不足道。”
评论
什么才算是“短”字符串?
–TheDevOpsGuru
2012年4月9日19:03
@AndHeCodedIt取决于我假设的系统速度。运行基准测试。
–丹·贝查德(Dan Bechard)
15年7月27日在12:43
#7 楼
我想补充一点,还有另一个区别。这与安德鲁发布的内容有关。也与在我们的软件中发现错误非常烦人。请参见下面的简化示例(我也省略了null检查)。
public const int SPECIAL_NUMBER = 213;
public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}
这将编译并始终返回
false
。虽然以下内容会产生编译错误:public const int SPECIAL_NUMBER = 213;
public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
return (numberTextBoxTextValue == SPECIAL_NUMBER);
}
我们必须解决一个类似的问题,即有人使用
Equals
比较了不同类型的枚举。您将要仔细阅读这多次,然后才意识到这是导致错误的原因。特别是如果SPECIAL_NUMBER
的定义不在问题区域附近。这就是为什么我真的反对在没有必要的情况下使用Equals的原因。您会失去一点类型安全性。
评论
这就是为什么最好使用静态string.Equals方法始终与StringComparison参数一起使用的原因-尝试比较字符串和整数时,重载将产生编译错误
–马雷克
2012年11月23日在16:44
我希望方法和运算符参数可以具有属性(并且Equals和ReferenceEquals一直使用它们)将禁止隐式转换,转换,装箱转换或上述各项的组合。我还希望使用==以外的其他运算符进行引用相等。用Equals和==定义所有参数类型的等效关系,并在不产生等效关系的情况下进行编译,将比使用它们进行编译更有帮助。
–超级猫
2013年9月27日19:06
#8 楼
我一直在试图解决一个错误,这是我的头,因为我阅读了此页并得出结论,实际上在实践中并没有什么实质性的区别,所以我将在此发布此链接,以防其他人发现他们得到不同的结果<= =等于。对象==相等失败,但.Equals成功。这有意义吗?
string a = "x";
string b = new String(new []{'x'});
Console.WriteLine("x == x " + (a == b));//True
Console.WriteLine("object x == x " + ((object)a == (object)b));//False
Console.WriteLine("x equals x " + (a.Equals(b)));//True
Console.WriteLine("object x equals x " + (((object)a).Equals((object)b)));//True
评论
据我了解,第二个相等检查失败,因为Object == Object解析为System.Object.ReferenceEquals,而a和b是内存中的两个不同对象。其余的比较字符串对象的值。甚至最后一个比较(似乎为Object类型对象调用.Equals)(由于它是作为虚拟方法实现的),默认情况下也会调用String.Equals。
–Lovethenakedgun
20 Mar 30 '20 at 7:30
评论
回复:重复闭包-请注意,此问题专门针对字符串,而引用重复中的可接受答案是对象的一般情况。 .Net与Java的区别非常明显,因为==可用于比较C#中的字符串内容。由于null传播运算符的出现,最好使用equals,因为在两个字符串均为null的情况下,也可以非常简洁地返回false。像这样:if(firstString?.Equals(secondString)?? false)