374

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

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

4

8 回答 8

378

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

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

如果它们被键入objectT然后在这里看到其他关于泛型方法或运算符重载的答案,因为您肯定想使用 Equals 方法。

于 2009-11-02T01:58:45.653 回答
124

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,str4obj2引用是相同的。

obj并且obj2object type和其他人是string type

结论

  1. com1 : 结果 = (obj == str2);// 真
    • 比较objectstring执行引用相等检查
    • obj 和 str2 指向同一个引用,所以结果为真
  2. com2 : 结果 = (obj == str3);// 假
    • 比较objectstring执行引用相等检查
    • obj 和 str3 指向不同的引用,因此结果为 false
  3. com3 : result = (obj == str4);// true
    • 比较objectstring执行引用相等检查
    • obj 和 str4 指向同一个引用,所以结果为真
  4. com4 : 结果 = (str2 == str3);// 真
    • 比较stringstring执行字符串值检查
    • str2 和 str3 都是“字符串”,所以结果为真
  5. com5 : 结果 = (str2 == str4);// 真
    • 比较stringstring执行字符串值检查
    • str2 和 str4 都是“字符串”,所以结果为真
  6. com6 : 结果 = (str3 == str4);// 真
    • 比较stringstring执行字符串值检查
    • str3 和 str4 都是“字符串”,所以结果为真
  7. com7 : result = (obj == obj2);// false - 比较objectobject执行引用相等检查 - obj 和 obj2 指向不同的引用,因此结果为 false
于 2013-02-26T13:37:31.693 回答
90

== 和 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 保证),这意味着它是引用相等而不是值相等。

当您有两个明确键入为 System.String 的值时,== 具有值相等语义,因为编译器将 == 解析为 System.String.op_equal 而不是 System.Object.op_equal。

所以为了安全起见,我几乎总是使用 String.Equals 来代替我总是得到我想要的值相等语义。

如果其中一个值为 null,为了避免 NullReferenceExceptions,我总是使用静态String.Equals 方法:

bool true = String.Equals("a", "ba".Substring(1));
于 2013-09-30T19:51:12.093 回答
46

String.Equals确实提供了重载来处理大小写和文化感知比较。如果您的代码不使用这些,则开发人员可能只是习惯于 Java,其中(如 Matthew 所说),您必须使用 .Equals 方法进行内容比较。

于 2009-11-02T02:01:13.317 回答
36

这两种方法的功能相同——它们比较
正如 MSDN 上所写:

但是,如果您的字符串实例之一为空,则这些方法的工作方式不同:

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");
于 2012-04-12T11:35:53.113 回答
16

这篇文章有一篇文章,您可能会觉得很有趣,其中引用了 Jon Skeet 的一些话。好像用法差不多。

Jon Skeet 指出实例 Equals 的性能“在字符串较短时稍好——随着字符串长度的增加,这种差异变得完全不显着”。

于 2009-11-02T01:58:21.207 回答
8

我想补充一点,还有另一个区别。这与安德鲁发布的内容有关。

在我们的软件中发现错误也与非常烦人有关。请参阅以下简化示例(我也省略了空检查)。

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。你失去了一点类型安全性。

于 2012-10-15T12:57:15.587 回答
5

我一直在努力解决一个错误,因为我阅读了这个页面并得出结论,在实践中没有有意义的差异,所以我会在此处发布此链接,以防其他人发现他们得到不同的结果出 == 和等于。

Object == 相等失败,但 .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
于 2012-10-12T14:08:58.903 回答