引用相等性和值相等性

在 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. HTML5资源教程

    新款CSS3按钮组合 5组可爱CSS3按钮 Leave a reply 之前我分享过一些时尚的CSS3动画按钮,比如CSS3渲染Checkbox实现3D开关切换按钮.纯CSS3 3D按钮 按钮酷似牛奶 ...

  2. [OpenGL]配置GLFW

    注:本文可转载,转载请著名出处:http://www.cnblogs.com/collectionne/p/6937644.html.本文还会修改,如果不在博客园(cnblogs)发现本文,建议访问上 ...

  3. WPF 杂谈——Binding表达式

    不管是定义控件还是用户控件都会用到一个功能--绑定(Binding).书面的叫法:元素绑定.意思就是让绑定的元素实现数据同步.在笔者看来WPF引入这一个功能实在是太完美了.编程更加的具体化.特别是跟M ...

  4. tostring方法

    //__tostring()方法//输出内容时不报错 用法实例:class Ren{ public $name; public function __tostring() { return " ...

  5. angularjs应用prerender.io 搜索引擎优化实践

    上一篇博文(http://www.cnblogs.com/ideal-lx/p/5625428.html)介绍了单页面搜索引擎优化的原理,以及介绍了两个开源框架的优劣.prerender框架的工作原理 ...

  6. python 标准库 -- multiprocessing

    multiprocessing 与 threading.Thread 类似 multiprocessing.Process 创建进程, 该进程可以运行用 python 编写的函数. multiproc ...

  7. css实现选项卡

    <style> *{ margin: ; padding: ; text-decoration: none; list-style: none; outline:none; } .box{ ...

  8. 探索Windows命令行系列(2):命令行工具入门

    1.理论基础 1.1.命令行的前世今生 1.2.命令执行规则 1.3.使用命令历史 2.使用入门 2.1.启动和关闭命令行 2.2.执行简单的命令 2.3.命令行执行程序使用技巧 3.总结 1.理论基 ...

  9. MySQL如何有效的存储IP地址及字符串IP和数值之间如何转换

    mysql> select inet_aton('192.168.0.1'); +--------------------------+ | inet_aton('192.168.0.1') | ...

  10. CSS active选择器与CSS hover选择器

    <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...