Why would you use String.Equals over ==?
我最近被介绍到一个大型代码库,注意到所有的字符串比较都是使用
你认为这是什么原因?
很大一部分开发者基础来自Java背景,使用EDCOX1 0来比较字符串是错误的,不起作用。
在C中,没有(实际的)区别(对于字符串),只要它们被键入字符串。
如果它们被输入为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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 |
添加手表
1 2 3 4 5 | obj "String" {1#} object {string} str2 "String" {1#} string str3 "String" {5#} string str4 "String" {1#} string obj2 "String" {5#} object {string} |
现在看看
结论:
- 比较
object 和string 进行参考相等性检查 - obj和str2指向相同的引用,因此结果为真
- 比较
object 和string 进行参考相等性检查 - obj和str3指向不同的引用,因此结果为false
- 比较
object 和string 进行参考相等性检查 - obj和str4指向相同的引用,因此结果为真
- 比较
string 和string 进行字符串值检查 - str2和str3都是"字符串",所以结果是真的。
- 比较
string 和string 进行字符串值检查 - str2和str4都是"字符串",所以结果是真的。
- 比较
string 和string 进行字符串值检查 - str3和str4都是"字符串",所以结果是真的。
==和字符串之间有一个细微但非常重要的区别。equals方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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); } } } |
生成此输出:
1
2
3
4
5
6
7
8
9
10
11 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,如果其中一个值为空,我总是使用静态字符串。equals方法:
1 | bool true = String.Equals("a","ba".Substring(1)); |
两种方法在功能上都是相同的-它们比较值。如msdn上所写:
- 关于
String.Equals 方法-确定此实例和另一个指定的字符串对象具有相同的值。(http://msdn.microsoft.com/en-us/library/858X0YYX.aspx) - 关于
== —尽管字符串是引用类型,但相等运算符(== 和!= 的定义是为了比较字符串对象的值,而不是参考文献。这使得对字符串相等性的测试更加直观。(http://msdn.microsoft.com/en-en/library/362314fe.aspx)
但是,如果其中一个字符串实例为空,则这些方法的工作方式不同:
1 2 3 4 5 6 7 8 9 10 11 | 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"); |
这篇文章有一篇短文,你可能会发现它很有趣,引用了乔恩·斯基特的一些话。它的用途似乎差不多。
Jon Skeet states that the performance of instance Equals"is slightly better when the strings are short—as the strings increase in length, that difference becomes completely insignificant."
我想补充一点,还有另一个区别。这与安德鲁发表的文章有关。
在我们的软件中发现bug也很烦人。请参阅以下简化示例(我也省略了空检查)。
1 2 3 4 5 6 | public const int SPECIAL_NUMBER = 213; public bool IsSpecialNumberEntered(string numberTextBoxTextValue) { return numberTextBoxTextValue.Equals(SPECIAL_NUMBER) } |
这将编译并始终返回
1 2 3 4 5 6 | public const int SPECIAL_NUMBER = 213; public bool IsSpecialNumberEntered(string numberTextBoxTextValue) { return (numberTextBoxTextValue == SPECIAL_NUMBER); } |
我们必须解决一个类似的问题,即有人使用
这就是为什么我反对在不必要的情况下使用平等。你失去了一点类型安全性。
我一直在努力解决一个错误,因为我读了这一页,并得出结论,在实践中没有什么有意义的区别,所以我会在这里张贴这个链接,以防其他人发现他们从==和等于得到不同的结果。
对象==相等失败,但.equals成功。这有道理吗?
1 2 3 4 5 6 7 | 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 |