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


    概要

      本方介绍.net如何判断两个对象是否相等

    .Net有四个判等函数  

      1)Object.ReferenceEquals

      2)Object.Equals  

      3)对象实例的Equals

      4)==操作

      这四个函数之间有细微的关系,改变其中一个函数的实现会影响到其他函数的操作结果。

    Object.ReferenceEquals静态方法

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

      对于Object.ReferenceEquals这个静态函数,函数形势如下:  

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

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

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

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

    Object.Equals静态方法

      方法内部完成的工作:

    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()判等需要3个步骤。

      第1步:对象所属类型的==操作符执行结果;

      第2 步:对象是否空引用(同第1步一样,使用对象所属类型的==操作符判断);

      第3步:对象所属类型的Equals()方法;

      因此,类型是否实现了自身的Equals()成为Object.Equals()返回什么结果的重要因素。

    等价规则

      等价的意义就是自反、对称、传递。

      1)所谓自反,即:a==a;

      2)所谓对称:即:a==b; 则:b==a;

      3)所谓传递:即:a==b; b==c; 则: a==c;

      理解了等价的意义,那么实现或重写判等函数就要满足等价规则。

    Equlas()可以重载的对象实例方法 

    public override bool Equals( object right );

    自定义判等示例:

    public override bool Equals( object right )
    {
        //step1:  Check null
         if( right == null )
            return false;
     
        //step2:  check reference equality
        if( object.ReferenceEquals( this, right ) )
            return true;
     
        //step3:  check type
        if( this.GetType() != right.GetType() )
            return false;
     
        //step4:  convert to current type for Equals
         KeyData rightASKeyData = right as KeyData;
     
        //step5:  check members value
         return this.Data == rightASKeyData.Data;
    }

      如上代码增加了一个类型检查,即:if( this.GetType() != right.GetType() ),这部分,这是由于子类对象可以通过as转化成基类对象,从而造成不同类型对象可以进行判等操作,违反了等价关系。

    ==操作符,适用于值类型判等

    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函数。所以在编写自己类型的时候,要保留这种风格。

    string引用类型的特殊性

      string是一个特殊的引用类型

      1)对象分配的特殊 

    string str1= "hello";
    string str2= "hello;

      上面代码执行:

      .net为str1分配内存后,“hello"存储于内存堆中。

      .net为str2分配内存时会在名为“暂存表”的字符串集合中检查现有内存中已经分配过“hello"这个字符串,如果有,则将其引用分配给str2, 若无则分配新的内存空间。

      所以,上述代码执行后 str1、str2实际指向同一地址,即:Object.ReferenceEqulas(str1,str2)  //return true;

      2)对象引用操作的特殊 

      例如:   

    string str1 = "abcd"; 
    string str2 = str1; 
    str2 = "efgh";// str1 is still "abcd" here 

      当对于一个新的string类型是原有对象引用的时候,这点和一般的引用类型一样,但是当新的对象发生变化的时候,要重新分配一个新的地方,然后修改对象指向,上面代码执行str2="efgh",其引用不再指向str1,而是指向新分配内存引用。 

      因此对于string操作的时候,尤其发生变化的时候,会显得比较慢,因为其牵扯到”暂存表“查找相同字符串、内存地址重新分配,所以对于数据量比较大的字符串操作时,使用StringBuilder成为最佳实践。

    参考:

      http://blog.csdn.net/zhoufoxcn/article/details/1326904

  • 相关阅读:
    JavaScript跳转到指定页面并且到指定的tab切换窗口
    三层架构之基础篇(对数据库增删改查)
    三层架构之基础篇(三层架构模型)
    过一天不登QQ的生活
    MVC + EF 框架 对数据库做增删改查
    想说的话
    新的2019年,向上
    C#读取txt文档
    C#写的 电子邮件客户端(winform窗体)
    C# 鼠标任意拖动无边框窗体(调用API函数)。
  • 原文地址:https://www.cnblogs.com/ybtools/p/6427908.html
Copyright © 2020-2023  润新知