c#

位置:IT落伍者 >> c# >> 浏览文章

C#中的类型相等与恆等(Equality & Identity)


发布日期:2018年05月06日
 
C#中的类型相等与恆等(Equality & Identity)

CLR提供了可以区分类型的Equality 和Identity能力

Equality

如果两个对象是相同的类型并且它们各自带有相同和等值的属性

Equality必须满足三个必要条件reflexive symmetrics and transitive

reflexive: 自身相等及a==a 是永远成立的

symmetrics: 对象性及a==b成立那么b==a 也成立

transitive: 传递性及a==b b==c成立那么a==c 也成立

Identity

两个对象必须相等(意味着他们共享同一块内存区域)

CLR提供了至少四种方法来判断两个对象的等价性

Public static bool ReferenceEquals(object left object right);

Public static bool Equals(object left object right);

Public virtual bool Equals(object right);

Public static bool operator==(MyClass left MyClass right);

ReferenceEquals方法总是用来判断两个对象的Identity的不管是针对值类型还是引用类型所以针对值类型调用该方法总是会返回false因为值类型作为这个方法的参数时会进行装箱操作

静态的Equals方法提供了判断两个对象的Equality能力在其实现的内部调用了上述第三个虚拟的Equals方法和ReferenceEquals一样它们已经具备从底层判断两个对象的能力我们从来不会覆写这两个方法

实例Equals方法也是用来区分两个对象的Equality的

对于引用类型的对象它和ReferenceEquals方法几乎是一样的(因为判断两个引用类型是否的Equality往往从Identity上就可以区分)

而值类型的对象我们不仅要判断他们具有相同的对象类型还要判断他们的值相等值类型从SystemValueType继承而来ValueType已经重写了ObjectEquals()方法本来已经可以用来满足这些要求的但是ValueTypeEquals()方法不是很有效因为它必须要通过反射在不知道具体的派生类型中完成对它们所含有成员变量的值的比较因此建议在我们实现一个值类型的数据结构时同时重写ValueTypeEquals()方法

然而我们再回头看看引用类型有时两个引用类型的对象往往被用来进行类似值类型的比较比如String类型它虽然是引用类型但它也重写了Equals方法因为我们拿它来判断两个string是否相同(Equality)实际是希望判断它们是否具有相同的内容这是一个value semantics因此我们建议在考虑实现一个用作值语义环境下的引用类型时候也重写基类的ObjectEquals()方法

请参考MDSN或其它相关文档如何实现Equals方法的重写

上面的图示给了很好的例子来区分Equals和ReferenceEquals方法被用来做Equility和Identity判断的区别

==运算符是可由类重载的运算符它也是用来判断恆等的

对于未重载==的引用类型会比较两个引用类型是否引用同一个对象这跟引用类型的Equals()方法是一样的

对于未重载==的值类型该运算符会比较这两个值是否按位相等即是否这两个值中的每个字段都相等和Equals方法一样推荐在自定义值类型中也要重载==运算符因为也存在反射在效率上的影响

==运算符和Equals方法的区别在于多态表现上Equals方法是重写而==运算符是被重载这意味着除非编译器知道调用具体的重载版本否则它只是调用未重载的==版本

上一篇:基于C#的接口基础教程之三

下一篇:基于C#的接口基础教程之四