原文地址:不详

.Net有四个判等函数?不少人看到这个标题,会对此感到怀疑。事实上确是如此,.Net提供了ReferenceEquals、静态Equals,具体类型的Equals以及==操作符这四个判等函数。但是这四个函数之间有细微的关系,改变其中一个函数的实现会影响到其他函数的操作结果。

  首先要说的是Object.ReferenceEquals和Object.Equals这两个静态函数,对于它们俩来说,是不需要进行重写的,因为它们已经完成它们所要得做的操作。对于Object.ReferenceEquals这个静态函数,函数形势如下:

public static bool ReferenceEquals( object left, object right );

  这个函数就是判断两个引用类型对象是否指向同一个地址。有此说明后,就确定了它的使用范围,即只能对于引用类型操作。那么对于任何值类型数据操作,即使是与自身的判别,都会返回false。这主要因为在调用此函数的时候,值类型数据要进行装箱操作,也就是对于如下的形式来说。

int n = ;
Object.ReferenceEquals( n, n );

  这是因为对于n这个数据装箱两次,而每次装箱后的地址有不同,而造成Object.ReferenceEquals( n, n )的结果永远为false。

  对于第一个判等函数来说,没有什么好扩展的,因为本身已经很好地完成了它所要做的。

  对于第二个Object.Equals这个静态函数,其形式如下:

public static bool Equals( object left, object right );

  按照书中对它的分析,其大致函数代码如下:

public static void Equals( object left, object right )
{   
// Check object identity   
if( left == right )
  return true;   
// both null references handled above
  if( ( left == null ) || ( right == null ) )   
return false;
  return left.Equals( right );   
}

  可以说,Object.Equals这个函数完成判等操作,需要经过三个步骤,第一步是需要根据对象所属类型的==操作符的执行结果;第二步是判别是否为null,也是和第一步一样,需要根据类型的==操作符的执行结果;最后一步要使用到类型的Equals函数的执行结果。也就是说这个静态函数的返回结果,要取决于后面要提到的两个判等函数。类型是否提供相应的判等函数,成为这个函数返回结果的重要因素。

  那么对于Object.Equals这个静态方法来说,虽说接受参数的类型也属于引用类型,但是不同于Object.ReferenceEquals函数,对于如下的代码,能得出正确的结果。

int n = ;
Debug.WriteLine( string.Format( "{0}", Object.Equals( n, n ) ) );
Debug.WriteLine( string.Format( "{0}", Object.Equals( n, ) ) );

  这是因为在此函数中要用到具体类型的两个判等函数,不过就函数本身而言,该做的判断都做了,因此不需要去重载添加复杂的操作。

  为了更好的述说剩下两个函数,先解释一下等价的意义。对于等价的意义,就是自反、对称以及传递。

所谓自反,即a == a;

  而对称,是a == b,则b == a;

  传递是 a == b,b == c,则 a == c;

  理解等价的意义后,那么在实现类型的判等函数也要满足这个等价规则。

  对于可以重载的两个判等函数,首先来介绍的是类型的Equals函数,其大致形式如下:

public override bool Equals( object right );

  那么对于一个类型的Equals要做些什么操作呢,一般来说大致如下:

public class KeyData
{
private int nData;
public int Data
{
get { return nData; }
set { nData = value; }
}
public override bool Equals(object right)
{
//Check null
if (right == null)
return false;
//check reference equality
if (object.ReferenceEquals(this, right))
return true;
//check type   
if (this.GetType() != right.GetType())
return false;
//convert to current type
KeyData rightASKeyData = right as KeyData;
//check members value
return this.Data == rightASKeyData.Data;
}
}

如上增加了一个类型检查,即

 if( this.GetType() != right.GetType() )

  这部分,这是由于子类对象可以通过as转化成基类对象,从而造成不同类型对象可以进行判等操作,违反了等价关系。

  除此外对于类型的Equals函数来,其实并没有限制类型非要属于引用类型,对于值类型也是可以重载此函数,但是我并不推荐,主要是Equals函数的参数类型是不可变的,也就是说通过此方法,值类型要经过装箱操作,而这是比较影响效率的。

  而对于值类型来说,我推荐使用最后一种判等函数,即重载运算符==函数,其大致形式如下:

public static bool operator == ( KeyData left, KeyData right );

  对于一个值类型而言,其的大致形式应该如下:

    public struct KeyData
{
private int nData;
public int Data
{
get { return nData; }
set { nData = value; }
}
public static bool operator ==(KeyData left, KeyData right)
{
return left.Data == right.Data;
}
public static bool operator !=(KeyData left, KeyData right)
{
return left.Data != right.Data;
}
}

  由于==操作与!=操作要同步定义,所以在定义==重载函数的时候,也要定义!=重载函数。这也是.Net在判等操作保持一致性。那么对于最后一个判等函数,这种重载运算符的方法并不适合引用类型。这就是.Net经常现象,去判断两个引用类型,不要用==,而要用某个对象的Equals函数。所以在编写自己类型的时候,要保留这种风格。

  那么对于以上介绍的四种判等函数,会产生如下类似的对比表格。

操作  结果取决于 适用范围 建议
Object.ReferenceEquals 两个参数对象是否属于同一个引用 引用类型 不要用它来判断值类型数据
Object.Equals 参数类型自身的判等函数 无限制 考虑装箱操作对值类型数据产生的影响
类型的Equals 类型重载函数 无限制 考虑装箱操作对值类型数据产生的影响
类型的==重载 类型重载函数  无限制 不要在引用类型中重载此运算符;

  那么在编写类型判等函数的时候,要注意些什么呢,给出如下几点建议。

  首先,要判断当前定义的类型是否具有判等的意义;

  其次,定义类型的判等函数要满足等价规则;

  最后一点,值类型最好不要重载定义Equals函数,而引用类型最好不要重载定义==操作符。

【转】区别和认识.Net四个判等函数的更多相关文章

  1. 《Effective C#》:区别和认识四个判等函数

    .Net有四个判等函数?不少人看到这个标题,会对此感到怀疑.事实上确是如此,.Net提供了ReferenceEquals.静态Equals,具体类型的Equals以及==操作符这四个判等函数.但是这四 ...

  2. 区别和认识.net四个判等方法

    概要 本方介绍.net如何判断两个对象是否相等 .Net有四个判等函数 1)Object.ReferenceEquals 2)Object.Equals 3)对象实例的Equals 4)==操作符 这 ...

  3. C#中四个判等函数的认识

    donet提供了四个判等函数,分别是referenceEqual,静态Equal,具体类型Equal,和==. 首先来说,object.referenceEqual和静态Equal public st ...

  4. String工具类之“四个判空方式”StringUtils.isNotBlank和StringUtils.isEmpty和StringUtils.isBlank和StringUtils.isNotEmpty

    一.判断str字符串都不为空==>StringUtils.isNotBlank(String str); 1 /** 2 * <p>检查一个字符串是否非空("") ...

  5. Python学习系列(四)(列表及其函数)

    Python学习系列(四)(列表及其函数) Python学习系列(一)(基础入门) Python学习系列(二)(基础知识) Python学习系列(三)(字符串) 一.基本概念 1,列表是什么?     ...

  6. Sql Server函数全解<四>日期和时间函数

    原文:Sql Server函数全解<四>日期和时间函数   日期和时间函数主要用来处理日期和时间值,本篇主要介绍各种日期和时间函数的功能和用法,一般的日期函数除了使用date类型的参数外, ...

  7. JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

    JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...

  8. SQL Server -- 回忆笔记(四):case函数,索引,子查询,分页查询,视图,存储过程

    SQL Server知识点回忆篇(四):case函数,索引,子查询,分页查询,视图,存储过程 1. CASE函数(相当于C#中的Switch) then '未成年人' else '成年人' end f ...

  9. js进阶js中支持正则的四个常用字符串函数(search march replace split)

    js进阶js中支持正则的四个常用字符串函数(search march replace split) 一.总结 代码中详细四个函数的用法 search march replace split 二.js进 ...

随机推荐

  1. 正则和xml解析

    一般来说是xml解析的开销比正则大些.使用正则搜索,只需搜索<second>就能定位到你要的内容,而xml解析要把节点树在内存中建立起来,所以消耗内存会多些,速度可能会受到一些影响.但对于 ...

  2. JDK 工具列表

    jar — 一个创建和管理 jar 文件的工具. java — Java 应用启动器.在这篇文章里,开发和部署都是用的这个启动器. javac — Java 编译器. javadoc — API 文档 ...

  3. 如何用OpenCV自带的adaboost程序训练并检测目标

    参考博文: 1.http://blog.csdn.net/wuxiaoyao12/article/details/39227189 2.http://www.cnblogs.com/easymind2 ...

  4. 原始套接字(SOCK_RAW)

    本文转载:http://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html,在此感谢 原始套接字(SOCK_RAW). 应用原始套接字,我 ...

  5. ASP.NET Web API 2 中的属性路由使用(转载)

    转载地址:ASP.NET Web API 2 中的属性路由使用

  6. 在linux上安装psycopg2出错--Error: pg_config executable not found.

    这个错误可能是因为缺少PGSQL的相关库吧. 网上有很多解决办法,我最终用以下方式解决: yum install postgresql postgresql-devel python-devel

  7. hihoCoder挑战赛14 -1223

    描述 给定n个关于X的不等式,问最多有多少个成立. 每个不等式为如下的形式之一: X < C X <= C X = C X > C X >= C 输入 第一行一个整数n. 以下 ...

  8. 电赛菜鸟营培训(零)——Keil环境搭建

    一.Keil开发软件安装 1.安装keil软件 2.使用注册机进行破解 将方框内的ID号复制到注册机,然后得到License,放到最底下就可以完成了. 二.Keil工程搭建 表示参考数据手册,在这里建 ...

  9. Failed to load or instantiate

    Failed to load or instantiate: add this code in your xml: xmlns:android="http://schemas.android ...

  10. maven打的jars项目,log4j不会输出日志

    通过maven打完包,运行jars时,会输出警告 log4j:WARN No appenders could be found for logger (com.dlht.DataCenterSYNC. ...