C# 中有两种不同的相等:引用相等和值相等。值相等是大家普遍理解的意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。引用相等意味着要比较的不是两个对象,而是两个对象引用,这两个对象引用引用的是同一个对象。这可以通过简单的赋值来实现,如下面的示例所示:

System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b); //returns true

在上面的代码中,只存在一个对象,但存在对该对象的多个引用:ab。由于它们引用的是同一个对象,因此具有引用相等性。如果两个对象具有引用相等性,则它们也具有值相等性,但是值相等性不能保证引用相等性。

若要检查引用相等性,应使用 ReferenceEquals。若要检查值相等性,应使用 Equals 或 Equals。

重写 Equals


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

Equals 的新实现应该遵循 Equals 的所有保证:

  • x.Equals(x) 返回 true。

  • x.Equals(y) 与 y.Equals(x) 返回相同的值。

  • 如果 (x.Equals(y) && y.Equals(z)) 返回 true,则 x.Equals(z) 返回 true。

  • 只要不修改 x 和 y 所引用的对象,x.Equals(y) 的后续调用就返回相同的值。

  • x.Equals(null) 返回 false。

Equals 的新实现不应该引发异常。建议重写 Equals 的任何类同时也重写 System.Object.GetHashCode。除了实现 Equals(对象)外,还建议所有的类为自己的类型实现 Equals(类型)以增强性能。例如:

class TwoDPoint : System.Object
{
public readonly int x, y;

public TwoDPoint(int x, int y) //constructor
{
this.x = x;
this.y = y;
}

public override bool Equals(System.Object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}

// If parameter cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if ((System.Object)p == null)
{
return false;
}

// Return true if the fields match:
return (x == p.x) && (y == p.y);
}

public bool Equals(TwoDPoint p)
{
// If parameter is null return false:
if ((object)p == null)
{
return false;
}

// Return true if the fields match:
return (x == p.x) && (y == p.y);
}

public override int GetHashCode()
{
return x ^ y;
}
}

可调用基类的 Equals 的任何派生类在完成其比较之前都应该这样做。在下面的示例中,Equals 调用基类 Equals,后者将检查空参数并将参数的类型与派生类的类型做比较。这样就把检查派生类中声明的新数据字段的任务留给了派生类中的 Equals 实现:

class ThreeDPoint : TwoDPoint
{
public readonly int z;

public ThreeDPoint(int x, int y, int z)
: base(x, y)
{
this.z = z;
}

public override bool Equals(System.Object obj)
{
// If parameter cannot be cast to ThreeDPoint return false:
ThreeDPoint p = obj as ThreeDPoint;
if ((object)p == null)
{
return false;
}

// Return true if the fields match:
return base.Equals(obj) && z == p.z;
}

public bool Equals(ThreeDPoint p)
{
// Return true if the fields match:
return base.Equals((TwoDPoint)p) && z == p.z;
}

public override int GetHashCode()
{
return base.GetHashCode() ^ z;
}
}

Overriding Operator ==


默认情况下,运算符 == 通过判断两个引用是否指示同一对象来测试引用是否相等,因此引用类型不需要实现运算符 == 就能获得此功能。当类型不可变时,意味着实例中包含的数据不可更改,此时通过重载运算符 == 来比较值是否相等而不是比较引用是否相等可能会很有用,因为作为不可变的对象,只要它们具有相同的值,就可以将它们看作是相同的。建议不要在非不可变类型中重写运算符 ==

重载的运算符 == 实现不应引发异常。重载运算符 == 的任何类型还应重载运算符 !=。例如:

//add this code to class ThreeDPoint as defined previously
//
public static bool operator ==(ThreeDPoint a, ThreeDPoint b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}

// Return true if the fields match:
return a.x == b.x && a.y == b.y && a.z == b.z;
}

public static bool operator !=(ThreeDPoint a, ThreeDPoint b)
{
return !(a == b);
}

注意:------------------------

运算符 == 的重载中的常见错误是使用 (a == b)(a == null)(b == null) 来检查引用相等性。这会导致调用重载的运算符 ==,从而导致无限循环。应使用 ReferenceEquals 或将类型强制转换为 Object 来避免无限循环。

------------------------------

转载于:https://www.cnblogs.com/08shiyan/archive/2011/03/14/1983257.html

Equals() 和 运算符 == 重载准则 (C# 编程指南)相关推荐

  1. 为什么 Java 不支持运算符重载?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | Yujiaao 来源 | https://se ...

  2. java 漂亮的连接曲线_猜猜 Java 为什么不支持运算符重载?

    作者 | Yujiaao 来源 | https://segmentfault.com/a/1190000019962661 另一个类似的 Java 面试难题.为什么 C++ 支持运算符重载而 Java ...

  3. C# 重载 Equals() 方法、重载运算符、声明显隐式转换的简要整理

    自动生成 可以使用 JetBrains ReSharper 的代码生成功能来自动生成各种结构性的或可重载的成员,而不必自行手写,因为非常麻烦且易错. 如确需手写,可参考本文. 引用类型和值类型 本文不 ...

  4. c++重载运算符_C/C++编程笔记:运算符重载丨重载C++中的New和Delete运算符

    new和delete运算符也可以像C ++中的其他运算符一样重载.New和Delete运算符可以全局重载,也可以在特定类中重载. (1)如果使用某个类的成员函数来重载这些运算符,则意味着这些运算符仅针 ...

  5. 【黑马程序员 C++教程从0到1入门编程】【笔记4】C++核心编程(类和对象——封装、权限、对象的初始化和清理、构造函数、析构函数、深拷贝、浅拷贝、初始化列表、友元friend、运算符重载)

    黑马程序员C++教程 文章目录 4 类和对象(类属性[成员属性],类函数[成员函数]) 4.1 封装 4.1.1 封装的意义(三种权限:public公共.protected保护.private私有)( ...

  6. 海贼班 胡船长第一次直播笔记 运算符重载 工程开发规范 编程范式 编译链接 谷歌测试框架

    海贼班 胡船长第一次直播笔记 运算符重载 工程开发规范 编程范式 编译&链接 谷歌测试框架 我个人觉得讲到的点都讲得挺清楚的 运算符重载 工程开发规范 # include <iostre ...

  7. C++编程入门--运算符重载复数类

    题目:成运算符重载员函数形式实现复数类的四则运算 上机指导2中,我们以独立函数形式(非成员函数,非友元函数)实现了Complex附属类的加减乘除四则运算,这里要求用Complex成员函数形式实现Com ...

  8. C++学习笔记 - 阶段三:C++核心编程 - Chapter7:类和对象-C++运算符重载

    阶段三:C++核心编程 Chapter7:类和对象-C++运算符重载 运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 7.1 加号运算符重载 作用:实现两个自定义数 ...

  9. Python编程基础18:运算符重载

    文章目录 零.本讲学习目标 一.运算符重载概述 二.加法运算重载符 (一)概述 (二)案例演示 ( 三)课堂练习 三.索引与切片重载 (一)__getitem__方法 1.概述 2.方法代码 3.案例 ...

  10. c 运算符重载前置++_C ++运算符重载–综合指南

    c 运算符重载前置++ Hello, folks! In this article, we will understand a very interesting yet magical power p ...

最新文章

  1. python apktool_Python使用ApkTool和子进程反编译APK
  2. 大话RxJava:一、初识RxJava与基本运用
  3. 字符串反转python_Python 反转字符串(reverse)的方法小结
  4. python教程简易版_简洁的十分钟Python入门教程
  5. Aqua Data Studio【下载】ads-windows-x64-16.0.5
  6. 计时器小程序——由浅入深实例讲解
  7. Dubbo中的监控和管理
  8. ArcEngine开发之自定义工具
  9. 软件设计方法和设计决策
  10. SourcesTree使用手册1:与Git进行通信
  11. CSS 布局Float 【3】
  12. kalilinux装到u盘上的弊端_暗黑系统安装盘高达14G!kali linux在它面前顿然失色
  13. 微信小程序开发-view视图组件
  14. Word2013关于图表目录
  15. wex5 checkbox
  16. 女生做数据分析师累吗?零基础可以转行吗?
  17. matlab图像去散焦,matlab为图像加运动模糊和散焦模糊
  18. mac认证服务器无响应,无法连接认证服务器mac
  19. 强势增长的中国半导体封装企业,已站在“起跑线”上
  20. 【个人记录 | UNet | 整理ing】

热门文章

  1. firewalld-富规则使用内容事项:
  2. FR常用技巧逐步整理
  3. 自学TP5源码(一)
  4. Codeforces 832 D Misha, Grisha and Underground
  5. java基础(十一章)
  6. 【转载】linux tail命令的使用方法详解
  7. OpenCart支付宝付款接口(直接到账、担保交易、双接口)
  8. eclipse 使用心得
  9. MATLAB实现频数直方图——hist的使用
  10. hdu 1536 S-Nim (sg)