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

31 浏览
0 Comments

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

最近,我接触了一个庞大的代码库,并注意到所有的字符串比较都是使用String.Equals()而不是==。你觉得这是什么原因呢?

0
0 Comments

为什么会使用String.Equals而不是==?\n在使用==和String.Equals方法之间有一个微妙但非常重要的区别:\n```cs\nclass Program\n{\n static void Main(string[] args)\n {\n CheckEquality(\"a\", \"a\");\n Console.WriteLine(\"----------\");\n CheckEquality(\"a\", \"ba\".Substring(1));\n }\n static void CheckEquality(T value1, T value2) where T : class\n {\n Console.WriteLine(\"value1: {0}\", value1);\n Console.WriteLine(\"value2: {0}\", value2);\n Console.WriteLine(\"value1 == value2: {0}\", value1 == value2);\n Console.WriteLine(\"value1.Equals(value2): {0}\", value1.Equals(value2));\n if (typeof(T).IsEquivalentTo(typeof(string)))\n {\n string string1 = (string)(object)value1;\n string string2 = (string)(object)value2;\n Console.WriteLine(\"string1 == string2: {0}\", string1 == string2);\n }\n }\n}\n

输出结果如下:

cs\nvalue1: a\nvalue2: a\nvalue1 == value2: True\nvalue1.Equals(value2): True\nstring1 == string2: True\n----------\nvalue1: a\nvalue2: a\nvalue1 == value2: False\nvalue1.Equals(value2): True\nstring1 == string2: True\n

可以看到,==运算符返回了false,尽管两个字符串显然是相等的。为什么会这样呢?因为在泛型方法中使用的==运算符是由System.Object定义的op_equal方法解析的(该方法在编译时对T的唯一保证是System.Object),这意味着它是引用相等而不是值相等。
当你有两个明确类型为System.String的值时,==具有值相等的语义,因为编译器将==解析为System.String.op_equal而不是System.Object.op_equal。
所以为了保险起见,我几乎总是使用String.Equals,以便始终获得我想要的值相等语义。
为了避免其中一个值为null时出现NullReferenceExceptions,我总是使用静态的String.Equals方法:

cs\nbool true = String.Equals(\"a\", \"ba\".Substring(1));\n```\n在返回类型为Object的代码中,也会出现相关的问题。如果var myItem=GetItem()从数据库中读取一个Object,那么表达式\"Hi\".Equals(myItem)、myItem.Equals(\"Hi\")和Object.Equals(\"Hi\", myItem)如果返回的对象是一个包含两个字符\"Hi\"的字符串,则都将返回True,但是myItem == \"Hi\"或\"Hi\" == myItem将测试引用相等。VB.NET的\"Option Strict On\"语言更好,它的\"=\"运算符要么测试值相等,要么无法编译;对于引用相等的检查,可以使用\"Is\"运算符。\n如果我在csharppad.com上执行\"a\" == \"ab\".Substring(0, 1),我会得到true。如果使用String对象也是一样。解释呢?\n因为在你的例子中,编译器知道要调用System.String的==运算符重载。你必须小心的情况是当编译器不知道它是什么类型时,比如比较表达式被定义为T或System.Object类型时。\n你能解释一下为什么.Substring()会导致不同的行为吗?因为它返回一个字符串,而不是包装在对象中的字符串,为什么它没有与第一个检查相同的行为?对我来说,两者应该有完全相同的输出。在第二个例子中,它保证是一个字符串比较,就像在第一个例子中一样。\n比较是在一个不知道在编译时将执行字符串比较的泛型方法中进行的。因此,在泛型方法中使用的==运算符是一个object==运算符,而不是string==运算符。.Substring(1)产生不同结果的原因是该方法创建一个新的字符串对象,而不是可能重用已经具有相同值的另一个对象。因此,在泛型方法中,这两个具有相等值但不同对象的字符串被视为不同的。\n我认为主要原因是字符串联接。在第一次调用CheckEquality(\"a\", \"a\")时,\"a\"和\"a\"是编译时常量,因此被联接,而后者作为运行时值则没有被联接。

0
0 Comments

为什么会使用String.Equals而不是==?\n在上述内容中,我们对String.Equals和==进行了比较,得出了不同的结果。通过分析这些结果,我们可以得出以下结论:\n1. com1:比较了一个object和一个string,所以执行了引用相等性检查。由于obj和str2指向相同的引用,所以结果为true。\n2. com2:比较了一个object和一个string,所以执行了引用相等性检查。由于obj和str3指向不同的引用,所以结果为false。\n3. com3:比较了一个object和一个string,所以执行了引用相等性检查。由于obj和str4指向相同的引用,所以结果为true。\n4. com4:比较了两个string,所以执行了字符串值的检查。由于str2和str3都是\"String\",所以结果为true。\n5. com5:比较了两个string,所以执行了字符串值的检查。由于str2和str4都是\"String\",所以结果为true。\n6. com6:比较了两个string,所以执行了字符串值的检查。由于str3和str4都是\"String\",所以结果为true。\n7. com7:比较了两个object,所以执行了引用相等性检查。由于obj和obj2指向不同的引用,所以结果为false。\n通过这些比较结果,我们可以看出使用String.Equals和==操作符的不同之处。String.Equals方法是调用了Equals方法,而==操作符(除非被重载)是调用了ReferenceEquals方法。\n那么为什么会选择使用String.Equals而不是==操作符呢?这是因为在一些特定的情况下,我们需要对字符串的值进行比较,而不仅仅是比较引用是否相等。例如,在比较两个变量的值时,我们通常会使用String.Equals方法来确保它们的值相等。\n另外,我们还注意到在obj和str3的比较中,它们指向了不同的引用。这是因为\"String\"作为一个编译时常量,被放入了字符串池中,而typeof(string).Name作为一个运行时的值,没有被放入字符串池中。\n总之,尽管在一些情况下,我们可以使用==操作符进行引用相等性的比较,但在比较字符串的值时,使用String.Equals方法更为准确和可靠。

0
0 Comments

为什么会使用String.Equals而不是==?\n在开发者中,很大一部分可能来自于Java背景,他们在Java中使用==来比较字符串是错误的,而且不起作用。\n在C#中,只要字符串被声明为string类型,就没有(实际上的)区别。\n如果它们被声明为object或T类型,那么参考其他回答,它们谈到了泛型方法或运算符重载,你肯定要使用Equals方法。\n根据返回值而言,它们没有区别。.Equals提供了更多的选项,但是str1.Equals(str2)和str1 == str2得到的结果是一样的。我相信它们使用不同的方法来确定相等性,正如Jon Skeet的引用所示,但是它们给出了相同的值。\n就功能而言,它们是一样的,但在计算上有细微的差别。\n也许你可以详细说明或提供一个关于它们之间的区别的链接吗?\n从Blaenk的回答中得知:dotnetperls.com/string-equals-compare\n基本上,这归结为少一个null检查(因为你不必检查this是否为null)。\n难道string.Equals不被认为是微软最佳实践(通过FxCop)吗?\n有一个很大的区别。如果其中一个字符串为null,那么.Equals将抛出异常。\n例外情况是.Equals唯一抛出的异常,如果你尝试在一个为null的对象上调用它,比如string str1 = null; str1.Equals()。这不是.Equals的问题,任何函数都会发生这种情况,应该是不言自明的。两个比较的实际功能在给定相同输入的情况下总是完全相同的。\n正是我的观点,为什么要冒着NullReferenceException的风险?我宁愿使用a == b而不是a.Equals(b)。我错了吗?\n在C#中,你是完全正确的。但正如我在我的答案中所说的,来自其他背景的人可能习惯于其他方式,因为他们最熟悉的语言的工作方式不完全相同。\n上面的链接不再有效,但这个链接有效:dotnetperls.com/string-equals\nstring.Equals和==之间存在实际差异。\n我在过去的5分钟里遇到了一个例子,==和string.Equals产生了不同的结果。等式检查使用==为false,而使用string.Equals为true。这两个字符串是从读取XML文件创建的对象的string属性。它们在XML中是相同的。我目前没有解释,但认为这值得一提。我猜这是某种引用问题。\n听起来像是Xamarin/mono有bug。在.NET中,String == String应该使用值相等。请注意,这仅适用于两个实例都是string的情况!(object)\"a\" == (object)\"a\"将使用object的等式运算符,它将使用引用相等并在一个非平凡的例子中返回false(在此确切情况下,编译器将在两个等效的编译时常量中使用相同的内存)。参见下面vikas的回答。\n最好避免在比较字符串时使用==和!=运算符。\nstring.==运算符是否在内部和string.Equals做了相同的事情?\n“为什么冒着NullPointerException的风险?”-好吧,因为通常,如果我在比较字符串的时候,我将使用它们中的一个或两个,并且不希望它们中的任何一个为null,我希望尽快知道其中一个为null,以避免在未定义的条件下继续正常执行。NullPointerException并不是被创造出来是为了恶意,它是为了保护这种情况而存在的。当然,有些情况下你不在乎字符串是否为null,但我认为将不抛出异常的方法视为最佳方法并不合理。\n如果你比较两个字符串的其中一个为null时,我不想将我的比较包装在try/catch中来处理其中一个对象为null的情况。异常不邪恶,当我只是在if语句内部进行比较时,它们只是令人讨厌。\n当然,如我所说,有些情况下你不在乎字符串是否为null。我猜测在正常程序操作期间,更常见的是处理空字符串,而不是允许它们在程序中为null,但这可以是一种风格的决定。我只是试图提供为什么“冒险”NullPointerException的答案,我并不是说它必须总是按照我的方式来做。\n我猜我倾向于使我的程序明确使用空字符串作为正常输入,并有意将null字符串保留为错误,这样我就可以始终知道哪些是好的数据,哪些是坏的数据,但这并不一定是你的方式,还有其他方法。\n你仍然冒着错过一个null字符串的风险-作为传递给Equals()的参数。不要依赖NullPointerException来捕捉你的null值-如果你怀疑可能会有null,你应该进行检查。\n只有当你调用.Equals()的字符串为null时,它才会抛出异常。这就是为什么你应该/可以使用string.Equals()而不是myString.Equals()。\nJava的字符串“==”以与.NET字符串\'ReferenceEquals\'相同的方式“损坏”。基本上,对于任何使用字符串内联的语言(大多数,我想),你根本不能依赖于字符串标识相等性是有用或有意义的。

0