.net 中的相等性比较

引用相等性和值相等性

在 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 = 5;
int j = 6;
int k = 5;

// 输出 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 = 5;

// 输出 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 进行相等性比较
时间: 2024-10-29 19:10:22

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

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

第三章第五节 ADT和OOP中的等价性 1.==与equals ==是引用等价性 :而equals()是对象等价性. == 比较的是索引.更准确的说,它测试的是指向相等(referential equality).如果两个索引指向同一块存储区域,那它们就是==的.对于我们之前提到过的快照图来说,==就意味着它们的箭头指向同一个对象. equals()操作比较的是对象的内容,换句话说,它测试的是对象值相等(object equality).在每一个ADT中,equals操作必须合理定义 2.等价性

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

假如同一个标签被多个选择器选中,每个选择器都设置了相同的样式,浏览器中加载时这个样式听谁的? 不同选择器设置的同一个样式,只会选择一个进行加载,不会叠加. 为了解决听谁的问题,引入层叠性的概念. 层叠性:多个选择器选中同一个标签,设置同一个样式,浏览器中加载时,不会加载所有的属性值,挑选其中一个加载,其中一个值层叠/覆盖掉其他的值.   要实现层叠或覆盖就涉及到比较,下面就是比较选择器之间的权重的比较,权重的比较一共有两种情况:1.选择器选中了标签:2.选择器没有选中标签 首先说一下选择器的权重

关于DOM脚本编程中不唐突性的简单理解

参考自:<JavaScript DOM 高级程序设计>第一章 遵循最佳实践 DOM脚本是为文档增强行为和交互性,当然文档需要符合W3C标准(有待进一步的学习).DOM脚本编程依赖于JavaScript,在这里就需要考虑不唐突性(unobtrusiveness)要强调的是,脚本必须是不唐突的,要消除一些不必要的行为和令人讨厌的功能.要保证在没有JavaScript的情况下,页面标记是持续有效的,这些当然会牺牲一些美观效果,是页面看起来不再那么优雅. 有关不唐突性的两个关键词“渐进增强(progr

抽象数据类型(ADT)和面向对象编程(OOP)3.5 ADT和OOP中的等价性

instancsof动态类型检查.除了在判断是否与应生成的类型一样外都不使用,getClass()同样 ==引用等价性 equals()对象等价性  基本数据类型使用 在自定义ADT时需要重写Object的equals()   对象类型使用 a.equals(null) returns false equals()的自反性:自己等自己   传递性:a等b,b等c,则a等c   对称性:a等b,则b等a 重写equals()必须也要重写hashCode(),相等的对象必须具有相同的散列码,如果没有

面向对象中的封装性怎么理解?

封装这个解释,我一直喜欢用CPU作为例子CPU把所有的电阻电容门电路等都封装起来,只留出一些管脚(接口)让用户使用,CPU能暴露什么,不能暴露什么,是生产商设计决定的,用户不能直接操作CPU的电阻电容等等,但可以通过給管脚适当的电压来控制电阻电容等,也就是说用户不能直接访问CPU的属性,但是可以通过方法修改CPU的属性的值同样的一个类也是把属性算法(逻辑处理)封装起来,只留必要的方法(接口)让用户使用,一个类该暴露什么,不该暴露什么,由类的设计者根据需求设计决定的.private属性用户不能直接

python 写matlab中的加性高斯白噪声AWGN

定义 原始信号:x 噪声信号:n 信噪比:SNR 信号长度:N def wgn(x, snr): snr = 10**(snr/10.0) xpower = np.sum(x**2)/len(x) npower = xpower / snr return np.random.randn(len(x)) * np.sqrt(npower) t = np.arange(0, 1000000) * 0.1 x = np.sin(t) n = wgn(x, 6) xn = x+n # 增加了6dBz信噪

C#中出现访问性不一致的解决方法

如图,说访问性比另一个低,我想可能是,b调用a,但a的访问性比b低就会出现这种问题,随即百度了一波,最终就是这个原因

第十六章、例行性工作排程 (crontab)

1. 什么是例行性工作排程 1.1 Linux 工作排程的种类: at, crontab 1.2 Linux 上常见的例行性工作 2. 仅运行一次的工作排程 2.1 atd 的启动与 at 运行的方式: /etc/at.deny 2.2 实际运行单一工作排程: at, atq & atrm, batch 3. 循环运行的例行性工作排程 3.1 使用者的配置: /etc/cron.deny, crontab 3.2 系统的配置档: /etc/crontab 3.3 一些注意事项 4. 可唤醒停机期

事务四大特征:原子性,一致性,隔离性和持久性(ACID)

一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 准备工作:为了说明事务的ACID原理,我们使用银行账户及资金管理的案例进行分析. [sql] view plaincopyprint? // 创建数据库 create table account( idint primary key not null, namevarchar(40), moneydouble ); // 有两个人开户并存钱 insert into account valu