你为什么要使用String.Equals而不是==?

Jam*_*ead 306 c# string equals

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

你觉得这是什么原因?

Mat*_*ley 313

很可能很大一部分开发人员基础来自Java背景,==用于比较字符串是错误的并且不起作用.

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

如果它们被输入object或者T在这里看到其他答案,那就是谈论泛型方法或运算符重载,你肯定想要使用Equals方法.

  • 有一个很大的不同.如果其中一个字符串为null,则.Equals将抛出异常. (83认同)
  • @Mas:`.Equals`抛出的唯一异常是一个空引用异常,如果你试图在一个null的对象上调用它,即.`string str1 = null; str1.Equals()`.这不是`Equals()`的问题,任何函数都会发生这种问题,应该是不言而喻的.在给定相同输入的情况下,两次比较的实际功能始终完全相同. (28认同)
  • 不是返回的值.`.Equals`确实提供了更多的选项,但是`str1.Equals(str2)`与`str1 == str2`相同,就像你得到的结果一样.我相信他们使用不同的方法来确定相等性,因为Jon Skeets引用Blaenk提出的指示,但它们给出了相同的值. (7认同)
  • 上面的链接不再起作用,但这个链接:http://www.dotnetperls.com/string-equals (6认同)
  • @Yuriy也许您可以详细说明或提供差异的链接? (2认同)
  • @Matthew:正是我的观点,为什么要冒 NullReferenceException 的风险?我总是使用 `a == b` 而不是 `a.Equals(b)`。我对这个不感兴趣吗? (2认同)

vik*_*kas 94

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
Run Code Online (Sandbox Code Playgroud)

添加手表

obj     "String" {1#}   object {string}
str2    "String" {1#}   string
str3    "String" {5#}   string
str4    "String" {1#}   string
obj2    "String" {5#}   object {string}
Run Code Online (Sandbox Code Playgroud)

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

obj,str2,str4obj2引用是相同的.

obj并且obj2object type和其他人string type

结论:

  1. com1:result =(obj == str2); // true
    • 比较objectstring执行引用相等性检查
    • obj和str2指向相同的引用,因此结果为真
  2. com2:result =(obj == str3); // false
    • 比较objectstring执行引用相等性检查
    • obj和str3指向不同的引用,因此结果为false
  3. com3:result =(obj == str4); // true
    • 比较objectstring执行引用相等性检查
    • obj和str4指向相同的引用,因此结果为真
  4. com4:result =(str2 == str3); // true
    • 比较stringstring执行字符串值检查
    • str2和str3都是"String",因此结果为true
  5. com5:result =(str2 == str4); // true
    • 比较stringstring执行字符串值检查
    • str2和str4都是"String",因此结果为true
  6. com6:result =(str3 == str4); // true
    • 比较stringstring执行字符串值检查
    • str3和str4都是"String",因此结果为true
  7. com7:result =(obj == obj2); // false - 比较objectobject执行引用相等性检查 - obj和obj2指向不同的引用,结果为false

  • 上面所有情况的简单解释:`string.Equals(object,object)`**是**`object.Equals(object,object)`,它在第一个参数上调用`Equals`,与`==`运算符不同, ,除非重载,调用`ReferenceEquals`. (17认同)
  • 我认为``String``和`typeof(string).Name`是不同的引用的原因是前者,作为编译时常量,是[实习](http://msdn.microsoft.com/ en-us/library/system.string.intern.aspx),而后者作为运行时值不是. (6认同)
  • 回复:“ComX”。回到 DOS 的糟糕旧时代,我收到一些数据,其中有人将文件命名为“com3”(在本例中“Com”代表“社区”,而不是“比较”)..当然,当尝试访问该文件时,操作系统认为它是一个 com 端口,结果很有趣。30 年后,但我不会将“任何东西”命名为“com-whatever”,除非它确实是一个 com 端口。 (2认同)

And*_*ott 66

==和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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

生成此输出:

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
Run Code Online (Sandbox Code Playgroud)

您可以看到==运算符返回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));
Run Code Online (Sandbox Code Playgroud)

  • 因为在您的示例中,编译器知道调用“==”运算符的“System.String”重载。您必须小心的情况是编译器*不*知道它是什么类型,例如当比较表达式的类型为“T”或“System.Object”时。 (2认同)
  • @AndrewArnott你能详细说明为什么`.Substring()`会导致不同的行为吗?由于它返回一个“字符串”,而不是包装在“对象”中的“字符串”,为什么它没有与第一次检查相同的行为?对我来说,两者似乎应该具有完全相同的输出。在第二个示例中保证是字符串比较,就像在第一个示例中一样。 (2认同)
  • @Rob比较是在一个通用方法中完成的,该方法*不**在编译时不知道它将进行字符串比较。因此,泛型方法中使用的==运算符是object ==运算符,而不是string ==运算符。.Substring(1)产生不同结果的原因是该方法创建了* new *字符串对象,而不是可能重用另一个已经具有相同值的对象。因此,由于泛型方法将两个值相等但对象不同的字符串视为不同。 (2认同)

Mic*_*tta 37

String.Equals确实提供重载来处理套管和文化意识的比较.如果您的代码没有使用这些代码,那么开发人员可能只会习惯使用Java,其中(如Matthew所说),您必须使用.Equals方法进行内容比较.

  • 这应该会更高,因为文化感知(和明确区分大小写)比较更实用 - 例如 https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings# Recommendation_for_string_usage (3认同)

the*_*zar 22

两种方法都具有相同的功能 - 比较.因为它是用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");
Run Code Online (Sandbox Code Playgroud)


Jor*_*eña 16

有一个书面记录这篇文章,你可能会发现很有趣,从乔恩斯基特一些报价.似乎使用几乎是一样的.

Jon Skeet表示,当字符串很短时,实例Equals"的性能会稍好一些 - 随着字符串长度的增加,这种差异变得完全无关紧要."

  • 什么完全符合"短"字符串? (17认同)

And*_*rew 5

我一直在试图解决一个错误,这是因为我读了本页,并得出结论,在实践中并没有有意义的区别,因此我将在此发布此链接,以防其他人发现它们得到不同的结果等于=且等于。

对象==相等失败,但是.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
Run Code Online (Sandbox Code Playgroud)


Mat*_*els 5

我想补充说还有另一个不同之处.这与安德鲁发布的内容有关.

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

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}
Run Code Online (Sandbox Code Playgroud)

这将编译并始终返回false.虽然以下将给出编译错误:

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return (numberTextBoxTextValue == SPECIAL_NUMBER);
}
Run Code Online (Sandbox Code Playgroud)

我们不得不解决类似的问题,有人比较使用不同类型的枚举Equals.在意识到它是导致错误的原因之前,您将阅读这么多次.特别是如果定义SPECIAL_NUMBER不在问题区域附近.

这就是为什么我真的反对在没有必要的情况下使用Equals.你失去了一点类型安全性.

  • 这就是为什么使用静态string.Equals方法始终使用StringComparison参数是好的 - 在尝试比较字符串和整数时,该重载会产生编译错误 (2认同)