为什么你会使用String.Equals ==?

我最近被介绍给一个大的代码库,注意到所有的字符串比较都是使用String.Equals()而不是==

这是什么原因呢,你觉得呢?

很大一部分开发人员来自Java背景,使用==来比较字符串是错误的并且不起作用。

在C#中,只要将它们键入为字符串,就没有(实际的)区别(对于字符串)。

如果将它们键入为objectT那么请参阅这里讨论泛型方法或运算符重载的其他答案,因为您肯定希望使用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#}

objstr2str4obj2引用是一样的。

objobj2object type ,其他是string type

结论

  1. com1 :result =(obj == str2); // true
    • 比较objectstring因此执行参考相等性检查
    • obj和str2指向相同的引用,所以结果是真实的
  2. com2 :result =(obj == str3); // false
    • 比较objectstring因此执行参考相等性检查
    • obj和str3指向不同的引用,所以结果是错误的
  3. com3 :result =(obj == str4); // true
    • 比较objectstring因此执行参考相等性检查
    • obj和str4指向相同的引用,所以结果是真实的
  4. com4 :result =(str2 == str3); // true
    • 比较stringstring因此执行字符串值检查
    • str2和str3都是“String”,所以结果是真的
  5. com5 :result =(str2 == str4); // true
    • 比较stringstring因此执行字符串值检查
    • str2和str4都是“String”,所以结果是真的
  6. com6 :result =(str3 == str4); // true
    • 比较stringstring因此执行字符串值检查
    • str3和str4都是“String”,所以结果是真的
  7. com7 :result =(obj == obj2); // false – 比较objectobject所以执行引用相等性检查–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中写的:

但是如果你的一个字符串实例是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