[C#基础教程]之Equals,ReferenceEquals,==的区别

在.net中有几种比较相等的方法

  object的静态ReferenceEquals()

  object的静态Equals()

  object的示例Equals()

  运算符==

  下面介绍一下他们的区别和用法。

  

  ReferenceEquals

  ReferenceEquals用于比较引用类型的引用是是否指向同一个对象。它只能比较引用类型。当把值类型传给它的时候永远都会返回false,因为值类型作为参数的时候首先会装箱,经过装箱的值类型哪怕是指相等,但是也是两个不同的对象,所以变量是指向不同的对象,所以永远返回false。

?
int  x = 10;
int  y = 10;
bool  b1 = object .ReferenceEquals(x,y);

  这里结果肯定是返回false,但是如果是比较引用类型,如果是两个引用指向同一个对象,则为true。

  我们还是先定义实体类

?
public  class  Person
    {
        private  int  _personId;
 
        public  int  PersonId
        {
            get  { return  _personId; }
            set  { _personId = value; }
        }
 
        private  string  _firstName;
 
        public  string  FirstName
        {
            get  { return  _firstName; }
            set  { _firstName = value; }
        }
 
        private  string  _lastName;
 
        public  string  LastName
        {
            get  { return  _lastName; }
            set  { _lastName = value; }
        }
 
        public  Person() { }
 
        public  Person( int  personId, string  firstName, string  lastName)
        {
            this ._personId = personId;
            this ._firstName = firstName;
            this ._lastName = lastName;
        }
    }

  调用代码

?
Person person1 = new  Person(1, "Edrick" , "Liu" );
Person person2 = new  Person(2, "Meci" , "Luo" );
Person person3 = person2;
bool  br1= object .ReferenceEquals(person1,person2);
bool  br2 = object .ReferenceEquals(person2, person3);

  我们可以发现第一个返回false,第二个返回true。那么如果其中有一个对象为null,或者两个对象都为null呢?结果会为false,如果两个都为null呢?结果为true。他们不会引发异常。

 

  实例Equals

  实例Equals算是比较复杂的一个比较方法。实例Equals可以比较引用是否指向同一个对象,同时可以按值来比较对象。如果要按值比较对象,我们就需要重载Equals对象来实现我们的比较逻辑。同时Equals默认也支持比较值类型的相等。那么我们该怎么重载Equals来让对象具有值相等性的比较呢?

  MSDN给我们列出了一些准则

  • 除涉及浮点型的情况外,x.Equals(x) 都返回 true

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

  • 如果 x 和 y 都为 NaN,则 x.Equals(y) 返回 true

  • 当且仅当 x.Equals(z) 返回 true 时,(x.Equals(y) && y.Equals(z)) 才返回 true

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

  • x.Equals(nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing) 返回 false

  我们来看看重写代码

?
public  class  Person
  {
      private  int  _personId;
 
      public  int  PersonId
      {
          get  { return  _personId; }
          set  { _personId = value; }
      }
 
      private  string  _firstName;
 
      public  string  FirstName
      {
          get  { return  _firstName; }
          set  { _firstName = value; }
      }
 
      private  string  _lastName;
 
      public  string  LastName
      {
          get  { return  _lastName; }
          set  { _lastName = value; }
      }
 
      public  Person() { }
 
      public  Person( int  personId, string  firstName, string  lastName)
      {
          this ._personId = personId;
          this ._firstName = firstName;
          this ._lastName = lastName;
      }
 
      public  override  bool  Equals( object  obj)
      {
          if  (obj != null  && obj is  Person)
          {
              Person p = obj as  Person;
 
              return  (PersonId == p.PersonId) && (FirstName == p.FirstName) && (LastName == p.LastName);
          }
          else
          {
              return  false ;
          }
      }
 
      public  override  int  GetHashCode()
      {
          return  base .GetHashCode()^PersonId;
      }
  }

  调用代码

?
Person person1 = new  Person(1, "Edrick" , "Liu" );
Person person2 = new  Person(2, "Meci" , "Luo" );
Person person3 = person2;
Person person4 = new  Person(1, "Edrick" , "Liu" );
 
Console.WriteLine(person4.Equals(person1));
Console.WriteLine(person4.Equals(person2));

  我们可以看到结果,第一个为true,第二个为false。重载的时候不能出现异常。那么如果有一个类继承Person呢,我们又改如何比较派生类。

?
public  class  Student:Person
    {
        private  int  _studentNumber;
 
        public  int  StudentNumber
        {
            get  { return  _studentNumber; }
            set  { _studentNumber = value; }
        }
 
        public  Student() { }
 
        public  Student( int  personId, string  firstName, string  lastName, int  studentNumber)
        {
            this .PersonId = personId;
            this .FirstName = firstName;
            this .LastName = lastName;
            this ._studentNumber = studentNumber;
        }
 
        public  override  bool  Equals( object  obj)
        {
            if  (obj != null  && obj is  Person)
            {
                Student s = obj as  Student;
                return  base .Equals(obj)&&StudentNumber==s.StudentNumber;
            }
            else
            {
                return  false ;
            }
        }
 
        public  override  int  GetHashCode()
        {
            return  base .GetHashCode()^StudentNumber;
        }
    }

  调用代码

?
Student s1 = new  Student(1, "Edrick" , "Liu" , 1);
Student s2 = new  Student(2, "Meci" , "Luo" , 2);
Student s3 = new  Student(1, "Edrick" , "Liu" , 1);
 
Console.WriteLine(s1.Equals(s2));
Console.WriteLine(s1.Equals(s3));

  我们只需要调用父类的Equals方法和比较派生类中的新值。

 

  静态Equals

  这个方法算是比较有趣的一个方法了。这个方法也是静态的,它能比较引用,能比较值类型。如果比较的类型重载了实例的Equals,那么它也能也比较对象的值。所以它返回true有三种情况。

  1,引用指向同一个对象

  2,比较两个null

  3,重载了Equals的实例方法返回true

?
Student s1 = new  Student(1, "Edrick" , "Liu" , 1);
Student s2 = new  Student(2, "Meci" , "Luo" , 2);
Student s3 = new  Student(1, "Edrick" , "Liu" , 1);
Student s4 = s3;
 
Console.WriteLine( object .Equals(s1,s3));
Console.WriteLine( object .Equals(s4, s3));

  这两个都为true,这里静态的Equals跟静态的EqualsReference有一个区别,静态的Equals如果有一个参数为null会抛出异常。

  下面讨论一个有趣的现象,如果重载了Equals但是没有重载==运算符,会发生什么

?
Student s1 = new  Student(1, "Edrick" , "Liu" , 1);
Student s2 = new  Student(2, "Meci" , "Luo" , 2);
Student s3 = new  Student(1, "Edrick" , "Liu" , 1);
Student s4 = s3;
 
Console.WriteLine(s1==s3);
Console.WriteLine(s3==s4);

  第一个为false,第二个为true。这显然不符合我们意图,所以重载了Equals必须重载==,同样重载了==也必须重载Equals。这样符合我们的意图,也能确保在使用集合的时候,代码能按照我们的意图工作。因为集合coll[0]==co[0]其实比较的是引用,但是如果我们的Equals比较的是对象的值那么最后代码还是不能按照我的期望的运行。

 

  ==运算符

  ==号运算符其实跟实例的Equals没有多大的区别,==是运算符,而Equals是方法。他们都可以重写。默认都能比较引用和比较值。关于==的重载可以参考运算符一文中的运算符重载。

 

  总结他们的区别:

  ReferenceEquals:静态方法,不能重写,只能比较引用,如果有一个参数为null会返回false,不会抛出异常,如果比较值类型,则始终返回false。

  Equals:实例方法,默认可以比较引用也可以比较值,可以重写。可以按值比较对象。

  静态Equals:静态方法,不能重写。如果没有重写Equals,比较引用,或者比较值。如果重载了Equals方法。比较引用,或者比较值,或者按重写的Equals比较,如果其中一个参数为null,抛出异常

  ==运算符:可以按引用比较,也可以按值比较。可以重写。是操作运算符。

  最后需要的是,如果重载了Equals,则最好是重载GetHashCode,必须重载==运算符。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值