关于c#:为什么要使用String.Equals而不是==?

Why would you use String.Equals over ==?

本问题已经有最佳答案,请猛点这里访问。

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

你认为这是什么原因?


很大一部分开发者基础来自Java背景,使用EDCOX1 0来比较字符串是错误的,不起作用。

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

如果它们被输入为objectT,那么在这里可以看到其他关于泛型方法或运算符重载的答案,因为您肯定希望使用equals方法。


string.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
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}

现在看看{1#}{5#}

objstr2str4obj2引用相同。

objobj2object type,其他为string type

结论:

  • com1:result=(obj==str2);//真
    • 比较objectstring进行参考相等性检查
    • obj和str2指向相同的引用,因此结果为真
  • com2:result=(obj==str3);//false
    • 比较objectstring进行参考相等性检查
    • obj和str3指向不同的引用,因此结果为false
  • com3:result=(obj==str4);//真
    • 比较objectstring进行参考相等性检查
    • obj和str4指向相同的引用,因此结果为真
  • com4:result=(str2==str3);//真
    • 比较stringstring进行字符串值检查
    • str2和str3都是"字符串",所以结果是真的。
  • com5:result=(str2==str4);//真
    • 比较stringstring进行字符串值检查
    • str2和str4都是"字符串",所以结果是真的。
  • com6:result=(str3==str4);//真
    • 比较stringstring进行字符串值检查
    • str3和str4都是"字符串",所以结果是真的。
  • com7:result=(obj==obj2);//false&比较objectobject以便执行引用相等性检查&-obj和obj2指向不同的引用,因此结果为假

  • ==和字符串之间有一个细微但非常重要的区别。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));


    String.Equals确实提供了处理套管和文化感知比较的过载。如果您的代码不使用这些,则DEVS可能只是用于Java,在这里(如马修所说),必须使用.Erras方法来进行内容比较。


    两种方法在功能上都是相同的-它们比较值。如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)
    }

    这将编译并始终返回false。而下面将给出一个编译错误:

    1
    2
    3
    4
    5
    6
    public const int SPECIAL_NUMBER = 213;

    public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
    {
        return (numberTextBoxTextValue == SPECIAL_NUMBER);
    }

    我们必须解决一个类似的问题,即有人使用Equals比较不同类型的枚举。在意识到这是导致bug的原因之前,您将阅读多次。尤其是当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