C# 中 == 和 .Equals() 之间的区别

来源

C# 中 == 和 .Equals() 之间的区别

概述

在本文中,您将了解C# 中 == 和 .Equals() 之间的区别。== 和 .Equals() 既用于两个值类型数据项的比较,也用于两个引用类型数据项的比较。本文将解释这两者之间的基本区别。== 比较内容,也比较引用标识,而 .Equals() 只比较内容。

The ==Operator compares the reference identity as well as contents while the.Equals() method compares only contents.

以下是一些示例,以了解这两者之间的区别。

案例 1:同时使用 == 和 .Equals() 进行值类型比较

当您使用 == 或使用 .Equals() 比较值类型或原始数据类型( intdoublefloat等)时,比较始终基于内容。如果两个变量的值的内容相同,则返回true,否则返回false。

示例,值类型的比较:

int x = 2;
int y = 2;

Console.WriteLine(x == y); //True
Console.WriteLine(x.Equals(y)); //True

Console.WriteLine(x == 2.0); //True
Console.WriteLine(x.Equals(2.0)); //False

当我们使用 == 比较 x 和 2.0 时,值 2.0 被认为是 2;而使用 .Equals() 方法时,值 2.0 不被认为是 2,所以它们的输出不同。在此示例中,== 操作符对值类型执行按位相等比较,如果返回true,则意味着被比较的对象具有相同的二进制表示;而 .Equals() 方法只是比较内容,所以它返回 false。

案例 2:同时使用 == 和 .Equals() 的引用类型比较

当您比较对象(即引用类型)时,它们会根据引用(内部的内存指针)进行比较。

示例,引用类型的比较:

Employee obj1 = new Employee();
obj1.Name = "Tutorialsrack";

Employee obj2 = new Employee();
obj2.Name = "Tutorialsrack";

Console.WriteLine(obj1 == obj2); //False
Console.WriteLine(obj1.Equals(obj2)); //False

Employee obj3 = obj1;

Console.WriteLine(obj1 == obj3); //True
Console.WriteLine(obj1.Equals(obj3)); //True

在上面的示例中,我们创建了两个Employee类对象(obj1 和 obj2 ),并使用 == 和 .Equals() 比较这两个对象。两个对象的内容虽然相同,但它们都返回了 false 。因为是对它们内部的内存指针进行比较,它们引用的是不同的实例。

接着,我们又"创建"了Employee类的一个对象(obj3),并使用 == 和 .Equals() 比较 obj1 和 obj3,它们都将返回了 true。因为obj1obj3是对同一个实例的引用,具有相同的内存指针。

案例 3:同时使用 == 和 .Equals() 进行字符串和对象比较

在 C# 中,如果字符串的内容相同,那么认定它们指向相同的内存位置, == 和 .Equals() 都将返回 true。

//基于内容比较两个字符串
//通过双引号初始化的 string 对象 在堆中存储,如果字符串的内容相同,那么认定它们指向相同的内存位置
object str1 = "tutorialsrack";
object str2 = "tutorialsrack";
Console.WriteLine(str1 == str2);  //True
Console.WriteLine(str1.Equals(str2));  //True

//基于引用的比较:
//string 对象 不在堆中存储,即 string 对象是一个普通的引用类型
object str3 = new string(new char[] { 't', 'u', 't', 'o', 'r', 'i', 'a', 'l' });
object str4 = new string(new char[] { 't', 'u', 't', 'o', 'r', 'i', 'a', 'l' });
Console.WriteLine(str3 == str4);  //False,基于引用
Console.WriteLine(str3.Equals(str4));  //True,基于内容

//== 运算符进行类型检查;.Equals() 方法不进行类型检查
string str7 = "tutorialsrack";
object obj = "tutorialsrack";
Console.WriteLine(str7 == obj);  //True,编译时显示警告信息
Console.WriteLine(str7.Equals(obj));  //True

//== 运算符处理 null 而 .Equals() 方法不处理
string str5 = null;
string str6 = null;
Console.WriteLine(str5 == str6);  //True,两个都是 null 时,返回 true
Console.WriteLine(str5.Equals(str6));  //此处抛出错误 NullReferenceException

在上面的示例中,当我们为“str1”赋值时,它会创建一个字符串对象,并且在堆中存储“tutorialsrack” 。当我们为“str2”赋值时,会分配一个不同的对象。因此,本应该使用“引用类型的规则”来比较“str1”“str2”。但 == 和 .Equals() 值却是 true,因为在 C# 中,如果字符串的内容相同,那么认定它们指向相同的内存位置。

何时使用 == 运算符和 .Equals() 方法

== 运算符是 C# 运算符,而 .Equals() 方法是多态方法。换句话说, == 是一种语言特征,而 .Equals() 它是 OOP 在遵循多态方面的一个特征点。

因此,判断何时使用 == 运算符和 .Equals() 方法:

  • 使用 == 运算符,当您需要进行一些技术比较时,例如对内容进行类型检查并处理 null 值。
  • 使用 .Equals() 方法,当您需要进行一些语义比较(例如内容比较)并且不关心 null 值时。

C# 中 == 与 .Equals() 之间的区别

# == 运算符 .Equals() 方法
用法 基于技术 基于语义的
值类型 基于内容的比较以及按位比较 基于内容的比较
对象类型 基于引用的比较 基于引用的比较
string 基于内容的比较 基于内容的比较
非堆中存储的的 string 基于引用的比较 基于内容的比较
类型检查 在编译期间 在运行时
空值 它处理空值 它不能处理空值

我希望这篇文章能帮助你理解C# 中 == 运算符和 .Equals() 方法之间的区别。

重载 == 与 .Equals()

C# 中有两种不同的相等:值相等和引用相等。

  • 值相等,是大家普遍理解的,在意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。

  • 引用相等,意味着要比较的不是两个对象本身,而是两个对象的引用,判断这两个“对象引用”是否引用的是同一个对象。

    对于引用相等,.Net 提供了System.Object.ReferenceEquals(objA, objB);方法来判是否引用相等;如果 objA 是与 objB 相同的实例,或如果两者均为 null,则为 true,否则为 false

.Equals()

  • Equals 是一个虚方法,允许任何类重写其实现。表示某个值(本质上可以是任何值类型)或一组值(如复数类)的任何类都应该重写 Equals

    即,.Equals() 是冲着判断值相等去的,表示某个值或一组值的任何类都应该重写 Equals。。

  • Equals 的新实现不应该引发异常。

  • 建议重写 Equals 的任何类同时也重写 System.Object.GetHashCode

  • 除了实现 Equals(对象)外,还建议所有的类为自己的类型实现 Equals(类型)以增强性能。

== 运算符

  • 默认情况下,== 通过判断两个引用是否指示同一对象来测试引用是否相等,因此引用类型不需要实现运算符 == 就能获得此功能。
  • 当类型不可变时,意味着实例中包含的数据不可更改,此时通过重载运算符 == 来比较值是否相等而不是比较引用是否相等可能会很有用,因为作为不可变的对象,只要它们具有相同的值,就可以将它们看作是相同的。
  • 建议不要在非不可变类型中重写运算符 ==
  • 重载的运算符 == 实现不应引发异常。
  • 重载运算符 == 的任何类型还应重载运算符 !=
  • 运算符 == 的重载中的常见错误是使用 (a == b)(a == null)(b == null) 来检查引用相等性。这会导致调用重载的运算符 ==,从而导致无限循环。应使用 ReferenceEquals 或将类型强制转换为 Object 来避免无限循环。

关于重载,详情参阅:Equals() 和运算符 == 的重载准则(C# 编程指南)

posted @ 2022-04-24 14:48  误会馋  阅读(1204)  评论(0编辑  收藏  举报