引用相等性和值相等性

在 C# 中,相等性分为引用相等性值相等性。引用相等性是指,若两个引用类型的变量引用的是同一个对象,则它们具有引用相等性。
// x, y, z 都是引用类型变量
object x = new object();
object y = new object();
object z = x; // 输出 false,x 和 y 不具有引用相等性
Console.WriteLine(object.ReferenceEquals(x, y)); // 输出 true,x 和 z 具有引用相等性
Console.WriteLine(object.ReferenceEquals(x, z)); // 输出 true,x 和自身具有引用相等性
Console.WriteLine(object.ReferenceEquals(x, x));
值相等性是指,若两个变量----可以是引用类型或值类型----包含语义上相同的值,则它们具有值相等性。
int i = ;
int j = ;
int k = ; // 输出 false,i 和 j 不具有值相等性
Console.WriteLine(i.Equals(j)); // 输出 true,i 和 k 具有值相等性
Console.WriteLine(i.Equals(k)); // 输出 true,i 和自身具有值相等性
Console.WriteLine(i.Equals(i));

== 和 != 操作符

== 操作符用于判断两个变量是否相等,默认的实现是:
  • 对于字符串以外的引用类型,判断变量是否具有引用相等性
  • 对于值类型,判断变量是否具有值相等性
  • 对于字符串类型,判断变量是否具有值相等性
!= 操作符与 == 操作符含义相反 。
 
C#允许重载 == 和 != 操作符。规则是,若要重载其中的一个,则必须重载另一个。
 

Object.ReferenceEquals 静态方法

Object.ReferenceEquals 静态方法用于判断引用相等性,它接受两个 object 类型的参数:
 
int i = ;

// 输出 false,i 被装箱两次,是两个不同的对象,不具有引用相等性
Console.WriteLine(object.ReferenceEquals(i, i)); // 相当于:
object x = i;
object y = i;
Console.WriteLine(object.ReferenceEquals(x, y));

.net 框架的源码实现中,ReferenceEquals 方法使用 == 操作符进行判断:

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[System.Runtime.Versioning.NonVersionable]
public static bool ReferenceEquals (Object objA, Object objB) {
return objA == objB;
}

代码参考:http://referencesource.microsoft.com/#mscorlib/system/object.cs,4d607d6d56a93c7e

字符串相等性

在 .net 中,字符串是引用类型,但 == 运算符和 Equals 方法都使用值相等性对字符串进行比较。默认的比较方式是区分大小写的,有时我们希望进行不区分大小写的比较。因此 String 类还有一个 Equals 方法的重载,允许指定如何对字符串进行相等性比较:

public bool Equals(string value, StringComparison comparisonType)

StringComparison 参数允许指定要使用的区域性、大小写和排序规则。

字符串的例子提示相等性比较不是绝对的,两个相同的对象,可能在一个上下文中相等,而在另一个上下文中不相等。

Object.Equals 实例方法

Object.Equals 实例方法的签名是:
public virtual bool Equals(Object obj)

这是一个虚方法,具体行为取决于是否进行了重写。Object 中 Equals 方法的实现是,如果参数 obj 与当前对象是同一实例,则返回 true。

ValueType 重写了 Equals 方法:若两个值类型变量的类型相同,并且所有实例字段相等,则它们具有值相等性。ValueType 中的 Equals 方法使用反射实现,对性能略有影响。对于自定义值类型,可考虑重写 Equals 方法避免反射带来的性能损失。

Object.Equals 静态方法

这是实用工具性质的方法,用于判断两个变量是否相等,方法签名是:

public static bool Equals(Object objA, Object objB)
它的实现代码如下:
public static bool Equals(Object objA, Object objB)
{
if (objA == objB)
{
return true;
}
if (objA == null || objB == null)
{
return false;
}
return objA.Equals(objB);
}
 
分析:
1,若两个变量引用相同的对象,或都为 null,则返回 true。
2,若任意一个变量为 null,另一个不为 null,则返回 false。
3,若两个变量都不为 null,并且不引用同一对象,那么返回 objA.Equals(objB) 的结果。
 

重写 Object.Equals 实例方法

重写 Object.Equals 实例方法时,应遵循以下规则:

  • 自反:x.Equals(x) 应返回 true
  • 对称:x.Equals(y) 和 y.Equals(x) 应具有相同的结果
  • 传递:如果 x.Equals(y) 为 true,并且 y.Equals(z) 为 true,那么 x.Equals(z) 应为 true
  • 稳定:如果 x 和 y 未修改,那么连续调用 x.Equals(y) 应具有相同的结果
  • 当实参为 null 时,应始终返回 null。
  • 若重写 Equals 方法,那么还应重写 GetHashCode 方法,并且,两个相等对象的 GetHashCode 方法应返回相同的值

IEquatable<T> 泛型接口

IEquatable<T> 定义类型特定的相等性比较方法,此接口只定义了一个方法,签名为:

bool Equals(T other)

此接口是从 .net 2.0 开始伴随泛型集合引入的。在泛型集合上调用 Contains、IndexOf、LastIndexOf 和 Remove 等方法时,将使用此接口进行相等性比较。根据 MSDN 的说明,任何可能存储在泛型集合中的类都应实现此接口。

如果实现了 IEquatable 接口,还应重写 Object.Equals 实例方法和 Object.GetHashCode 方法。

IEqualityComparer<T> 泛型接口和 EqualityComparer<T> 泛型类

IEqualityComparer 声明了两个方法:

bool Equals(T x, T y)
int GetHashCode(T obj)

此接口允许在泛型集合中跳过 T 本身的 Equals 和 GetHashCode 实现,如果向泛型集合提供了 IEqualityComparer<T> 的实例,那么集合将使用 IEqualityComparer<T> 的 Equals 和 GetHashCode 方法进行比较。

EqualityComparer<T> 为 IEqualityComparer<T> 泛型接口的实现提供基类。EqualityComparer<T>.Default 属性返回默认的相等性比较器,IEquatable<T> 与泛型集合的配合实际上是在这里起作用的:

  • 若 T 实现了 IEquatable<T> 接口,则 EqualityComparer<T>.Default 使用 IEquatable<T> 接口进行相等性比较
  • 否则,EqualityComparer<T>.Default 使用 Object.Equals 进行相等性比较
 
 

.net 中的相等性比较的更多相关文章

  1. spring中的传播性 个人认为就是对方法的设置 其作用能传播到里面包含的方法上

    spring中的传播性 个人认为就是对方法的设置 其作用能传播到里面包含的方法上

  2. 如何在Django模型中管理并发性 orm select_for_update

    如何在Django模型中管理并发性 为单用户服务的桌面系统的日子已经过去了 - 网络应用程序现在正在为数百万用户提供服务,许多用户出现了广泛的新问题 - 并发问题. 在本文中,我将介绍在Django模 ...

  3. 【软件构造】第三章第五节 ADT和OOP中的等价性

    第三章第五节 ADT和OOP中的等价性 在很多场景下,需要判定两个对象是否 “相等”,例如:判断某个Collection 中是否包含特定元素. ==和equals()有和区别?如何为自定义 ADT正确 ...

  4. Flume-NG中Transaction并发性探究

    我们曾经在Flume-NG中的Channel与Transaction关系(原创)这篇文章中说了channel和Transaction的关系,但是在source和sink中都会使用Transaction ...

  5. 探究CSS中的包裹性

    之前一直都知道css中的部分元素具有包裹性,今天写博客的时候正好也遇到了一个,所以想总结一下,有错误的地方欢迎指出来. 什么是包裹性? 包裹性就是父元素的宽度会收缩到和内部元素宽度一样. 哪些元素具有 ...

  6. css中的层叠性及权重的比较

    假如同一个标签被多个选择器选中,每个选择器都设置了相同的样式,浏览器中加载时这个样式听谁的? 不同选择器设置的同一个样式,只会选择一个进行加载,不会叠加. 为了解决听谁的问题,引入层叠性的概念. 层叠 ...

  7. 前端设计师如何提高UI界面中的阅读性

    阅读体验是ui设计中必不可少的一项,良好的设计应该都是可读的设计,如果信息都无法正常而清晰的传达,那么设计就失去了意义.设计的可读性和排版设计息息相关,这也就跟设计师的设计功底息息相关.下面简单介绍文 ...

  8. JavaScript中各存在性函数

    JavaScript中有很多表示存在性和从属关系的函数,本文介绍如下几个: 1)有关实例与构造函数原型之间的关系:isPrototypeOf(),Object.getPrototypeOf(); 2) ...

  9. JS中的相等性判断===, ==, Object.is()

    首发地址:http://www.geeee.top/2019/11/15/equality-comparisons/,转载请注明出处 相信刚接触JS的人都会被他的想等性判断给整糊涂,看看下面代码,你能 ...

随机推荐

  1. AVL树(平衡二叉查找树)

    首先要说AVL树,我们就必须先说二叉查找树,先介绍二叉查找树的一些特性,然后我们再来说平衡树的一些特性,结合这些特性,然后来介绍AVL树. 一.二叉查找树 1.二叉树查找树的相关特征定义 二叉树查找树 ...

  2. Maven基本安装与配置

    百度Maven,进入Maven官网,点击Download 点击下载Binary zip包,下载到电脑上相应的位置即可. 找到下载文件,进行解压,解压到相应的文件夹下面,并且记住路径. 打开系统-> ...

  3. java基础(十一章)

    一.理解什么是类和对象               万事万物皆对象 1.属性--对象具有的特征(特点) 2.方法--对象可执行的操作(能干什么事) 3.对象的定义: 是一个客观存在的,看的见或摸得着的 ...

  4. 用java来实现验证码功能(本帖为转载贴),作为个人学习收藏用

    一.关于为何使用验证的解释 在目前的网页的登录.注册中经常会见到各种验证码.其目的便是为了:防止暴力破解  .因为只要CPU性能较强,便可以在慢慢尝试密码的过程中来破解用户账号,因而导致的结果是用户信 ...

  5. Spring学习(21)--- AOP之Advice应用(上)

    前置通知(Before advice) 在某个连接点(join point)之前执行的通知,但不能阻止连接点前的执行(除非它抛出异常) 返回后通知(After returning advice) 在某 ...

  6. Java基本之数据类型

    一.创建一个简单的Java应用程序 public class Code { public static void main(String[]args) { System.out.println(&qu ...

  7. ubuntu eclipse 建立server 提示coud not load the tomcat server configuration at /opt/apache ...的解决方法

    ubuntu eclipse 建立server 提示coud not load the tomcat server configuration at /opt/apache ...的解决方法 & ...

  8. JavaScript表单验证和正则表达式

    JavaScript表单验证 分为四类: 1.非空验证 常用于用户名等 2.相等验证 常用于验证两次输入的密码 3.范围验证 常用于年龄等 4.正则验证 用于手机号,邮箱号等 以下是实例: <! ...

  9. word和.txt文件转html 及pdf文件, 使用poi jsoup itext心得

    word和.txt文件转html 及pdf文件, 使用poi jsoup  itext心得本人第一次写博客,有上面不足的或者需要改正的希望大家指出来,一起学习交流讨论.由于在项目中遇到了这一个问题,在 ...

  10. 高考志愿填报:java 软件 程序员 目前的就业现状

    大约在17年前,也就是2000年,学计算机专业的学生可以有大部分都进入本专业,并且就业非常容易.哪怕只会office套件,想找个工作也很简单.那时候学计算机就是最热门的行业. 那时候,搞Java的还是 ...