使用[==]运算符和.Equals()方法比较Int、Char、Object数据类型

3

我对这段代码感到困惑,两个条件之间有什么区别?为什么结果不同?

示例1 - datatype不同但值相同,结果为true

 int value1 = 'a';
 char value2 ='a'; 
 Console.WriteLine(value1 == value2);
 Console.WriteLine(value1.Equals(value2));



例子二 - 它们具有相同的数据类型和相同的值,但它返回false & true

object obj1 = "Object One";
object obj2 = new string("Object One".ToCharArray());
Console.WriteLine(obj1 == obj2);
Console.WriteLine(obj1.Equals(obj2));

intchar在编译器中拥有一些神奇的支持,这就是为什么这两个之间允许出现的内容对于其他任何东西都不可表示。 - Lasse V. Karlsen
2
简单来说,你看似简单的代码中实际上涉及到了很多需要详细解释的内容。 - Lasse V. Karlsen
4个回答

10

实际上,在您的问题中看似简单的代码中有很多内容需要处理,因此让我们逐步进行。请注意,有很多东西正在进行,我可能会错过一些细节,请使用评论区提出。

首先处理第一段代码:

int value1 = 'a';
char value2 ='a'; 
Console.WriteLine(value1 == value2);
Console.WriteLine(value1.Equals(value2));

这行文字:

int value1 = 'a';

这应该能提示您此代码行为的原因。从charint存在一个静默转换。实际上,编译后的内容并没有提到这个变量是一个char,它是一个数字。赋给int变量的数字是a的码点值,即97。

第一个比较:

value1 == value2

int 上使用 == 运算符进行比较,实际上是进行了纯数字比较,就好像字符是一个数字一样。这里也发生了相同的静默转换,字符被转换为数字。既然是相同的字符和相同的转换,那么从这个比较中你最终得到的结果也应该是 97。

这在规范的第 6.1.2 节“隐式数字转换”中提到:

隐式数字转换包括:
...
charushortintuintlongulongfloatdoubledecimal

这意味着实际上所写的等同于:

97 == 97

第二个比较:

value1.Equals(value2)

使用完全相同的转换进行完成,因此您拥有:

97.Equals(97)

因此,通过添加显式强制转换并更改代码以符合编译器的视图,让我们使第一段代码变得非常清晰:

// int value1 = (int)'a';                        // 97
int value1 = 97;
char value2 = 'a';
Console.WriteLine(value1 == (int)value);         // 97 == 97
Console.WriteLine(value1.Equals((int)value2));   // 97.Equals(97);

我还让LINQPad展示了这两个语句的反编译:

int a = 97;
int a = 'a';

它们都编译为:

ldc.i4.s 61             // 0x61 = 97

为了明确,这种静默转换是由编译器完成的,对于声明来说没有将字符转换成整数的运行时代码,代码执行并被编译就像您实际编写的一样。

int value1 = 97;

所以这就是这部分的原因。

现在转到下一部分:

object obj1 = "Object One";
object obj2 = new string("Object One".ToCharArray());
Console.WriteLine(obj1 == obj2);
Console.WriteLine(obj1.Equals(obj2));

在这里,您首先声明了两个object变量,这一点非常重要,然后给它们赋相同的string,虽然它们是两个不同的实例

那么让我们处理第一个比较:

obj1 == obj2

这是使用为object定义的==运算符完成的,它比较引用。由于我们已经确定了第二个变量的奇怪字符串构造会构建一个新实例,因此引用比较表明它们是不同的。

之所以使用在object上定义的==运算符,而不是在string上定义的运算符,是因为运算符在编译时被解析,而编译器只知道变量是object类型。它们包含字符串这一事实,甚至编译器可以“看到”您刚刚将字符串赋值给它们,以便应该使用string==运算符来代替,但被忽略了。

然而,当你这样做:

obj1.Equals(obj2)

那么您正在调用在object中声明的虚拟.Equal(object other)该方法在string中被重写,因此您得到了字符串内容比较,这表明它们是相同的。

因此让我们将第二段代码也表述得非常清楚:

object obj1 = "Object One";
object obj2 = new string("Object One".ToCharArray());
Console.WriteLine(obj1.ReferenceEquals(obj2));          // <-- changed
Console.WriteLine(obj1.Equals(obj2));

2
在示例1中,int和char是值类型,因此等式比较(通过==或Equals)默认为逐位比较(如此处所述),因为它们中的任何一个都没有覆盖==,他们的Equals实现将工作委托给==。
在这两种情况下都返回true,因为value1和value2具有相同的二进制表示。
在示例2中,string是引用类型,obj1和obj2是指向两个字符串实例的引用,它们恰好具有相同的内容。
但是由于它们声明为对象,并且==在编译时解析,编译器唯一的选择是发出引用比较(= false)。
相比之下,obj1.Equals实际上是调用string.Equals(object),它将返回字符串值的比较。

1
Example1:

示例1

int 的值为 97char 的值也是如此。 (参见 ASCII)
两者都是值类型,因此每次都会比较值。

Example2:

示例2

字符串是引用类型。
因此使用 .Equals 比较值(相同),而 == 比较引用,其不同。


这可能是相反的,因为“==”是静态解析的,将使用引用比较,而“Equals”是动态解析的。 - vc 74
但是值相同,但在使用“==”和.equals()时结果不同,这是什么区别? - davinceleecode
这并不像“每次都进行值比较”那么简单,char和int在编译器中有神奇的支持,使它们的行为与其他比较不同。如果您创建两个具有int的结构体,这也是两个值类型,则必须专门实现==,因此无论==正在执行什么操作完全取决于程序员。 - Lasse V. Karlsen
1
@Squirrelintraining 简而言之,在示例2中,==将比较引用,因为编译器不知道obj1和obj2是字符串,并且运算符在静态(编译时)解析,与Equals不同,后者将在运行时动态解析,由于obj1和obj2实际上是字符串,它们的值将被比较。我认为OP颠倒了两个结果。 - vc 74
1
@vc74 是的,他把它倒过来了。我在交互式 shell 中运行了代码,结果却颠倒了。我已经编辑了我的答案。 - Squirrel in training
显示剩余2条评论

0

示例1

这里发生了隐式转换,由于两者都是值类型,因此比较的不是引用,结果为true。更进一步解释,发生了以下情况:

int value1 = 'a';           //First converts to ASCII value 97 and then stored in value1
char value2 ='a';           //Stored as a
Console.WriteLine(value1);  //output is 97
Console.WriteLine(value2);  //output is a
Console.WriteLine(value1 == value2);   //compares using implicit conversion. Since value type, so only value comparison and hence true 
Console.WriteLine('a' == 97);          //compares using implicit conversion.  Since value type, so only value comparison and hence true  
Console.WriteLine(value1.Equals(value2)); //compares using implicit conversion.  Since value type, so only value comparison and hence true 

例子2 -

在这里,您手动使用了从Char到String的转换,因此发生了显式转换。更具体而言,发生了以下情况:

object obj1 = "Object One";     //string value is stored in Object type variable
object obj2 = new string("Object One".ToCharArray());  //Explicit conversion
Console.WriteLine(obj1);        //Output is Object One
Console.WriteLine(obj2);        //Output is Object One
Console.WriteLine(obj1 == obj2);  //Since == compares both reference and value, hence the false output
Console.WriteLine(obj1.Equals(obj2));  //Equals() compares just the value, hence the true result

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接