为什么你会使用String.Equals ==?
我最近被介绍给一个大的代码库,注意到所有的字符串比较都是使用String.Equals()
而不是==
这是什么原因呢,你觉得呢?
很大一部分开发人员来自Java背景,使用==
来比较字符串是错误的并且不起作用。
在C#中,只要将它们键入为字符串,就没有(实际的)区别(对于字符串)。
如果将它们键入为object
或T
那么请参阅这里讨论泛型方法或运算符重载的其他答案,因为您肯定希望使用Equals方法。
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 :result =(obj == str2); // true
- 比较
object
和string
因此执行参考相等性检查 - obj和str2指向相同的引用,所以结果是真实的
- 比较
- com2 :result =(obj == str3); // false
- 比较
object
和string
因此执行参考相等性检查 - obj和str3指向不同的引用,所以结果是错误的
- 比较
- com3 :result =(obj == str4); // true
- 比较
object
和string
因此执行参考相等性检查 - obj和str4指向相同的引用,所以结果是真实的
- 比较
- com4 :result =(str2 == str3); // true
- 比较
string
和string
因此执行字符串值检查 - str2和str3都是“String”,所以结果是真的
- 比较
- com5 :result =(str2 == str4); // true
- 比较
string
和string
因此执行字符串值检查 - str2和str4都是“String”,所以结果是真的
- 比较
- com6 :result =(str3 == str4); // true
- 比较
string
和string
因此执行字符串值检查 - str3和str4都是“String”,所以结果是真的
- 比较
- com7 :result =(obj == obj2); // false – 比较
object
和object
所以执行引用相等性检查–obj和obj2指向不同的引用,所以结果是false
==和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方法(这是方法在编译时的唯一保证),这意味着它是引用相等而不是值相等。
如果显式键入了两个作为System.String的值,则==具有值相等的语义,因为编译器将==解析为System.String.op_equal而不是System.Object.op_equal。
所以为了安全起见,我几乎总是使用String.Equals,而我总是得到我想要的值相等语义。
而要避免NullReferenceExceptions,如果其中一个值为null,我总是使用静态 String.Equals方法:
bool true = String.Equals("a", "ba".Substring(1));
String.Equals
确实提供了重载处理框架和文化意识的比较。 如果你的代码没有使用这些,开发人员可能只是使用Java,在那里(正如马修说的),你必须使用.Equals方法来做内容比较。
有关这篇文章的文章 ,你可能会发现很有趣,用Jon Skeet的一些引用。 这似乎是使用几乎相同。
Jon Skeet指出,实例Equals的表现“稍微好一些,当字符串很短时,随着字符串长度的增加,差异变得完全不重要”。
两种方法都具有相同的功能 – 比较值 。 正如它在MSDN中写的:
- 关于String.Equals方法 – 确定此实例和另一个指定的String对象是否具有相同的值。 ( http://msdn.microsoft.com/en-us/library/858x0yyx.aspx )
- 关于'==' – 虽然string是一个引用类型,但是定义相等运算符(==和!=)是为了比较字符串对象的值,而不是引用。 这使得对字符串相等的测试更直观。 ( http://msdn.microsoft.com/en-en/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");
我想补充说的是还有另一个区别。 这与安德鲁的帖子有关。
这也是一个非常烦人的发现我们的软件中的错误。 看下面的简单例子(我也省略了空检查)。
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。 你失去了一些类型安全。
我刚刚敲了一下墙,试图解决一个错误,因为我读了这个页面,结果没有什么实际意义上的差异,所以我会在这里发布这个链接,以防其他人发现他们得到不同的结果出于==和等于。
对象==相等失败,但.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