C#学习笔记第四篇之Equals,GetHashCode ,ToString函数深度剖析(一)



       学JAVA的时候也是经常碰到这三个函数,因为不是经常用,所以也不熟悉具体有什么用,有次看视频,看到一个老师讲到前两个函数,有大致的印象,最近学C#的时候又碰到了这三个函数,正好碰上要学习C#中的各种容器,才发现这个三个函数是如此的重要。如果不知道,不会用,这三个函数,只能说明自己的C#或者JAVA水平都还是刚入门的。OK,废话不多说,言归正传,来具体详细探讨这每一个函数的细节,主要参考的MSDN的原文档,写的非常好有木有?虽然英文的,但是读起来很清晰。参考文献http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx



Equals函数:

1、 The type of comparison between the current instance and the obj parameter depends on whether the    current instance is a reference type or a value type.

    当前实例与参数对象的比较类型取决于当前对象是引用类型还是值类型,这一点非常重要,下面的例子中会详细讲述。

2、If the current instance is a reference type, the Equals(Object) method tests for reference equality, and a call to the Equals(Object) method is equivalent to a call to the ReferenceEquals method. 


     如果当前实例是一个引用类型,那么该函数比较的是两个对象的引用值是否相当,而不是比较对象中内容是否相等。

            Box b1 = new Box(1, 1, 1);
            Box b2 = new Box(1, 1, 1);
            Box b3 = b1;
            //b1==b2?
            Console.WriteLine("b1 == b2 : " + b1.Equals(b2));//false 
            //b3 = b1?
            Console.WriteLine("b3 == b1 : " + b1.Equals(b3));//true
    
    public class Box
    {
        public Box(int x, int y, int z)
        {
            this.height = x;
            this.length = y;
            this.width = z;
        }
        public int height { get; private set; }
        public int length { get; private set; }
        public int width { get; private set; }
    }

3、如果是值类型,那么比较的是就是该值的值,但是要注意的是参与比较的两个值,类型必须一样,在值相等的情况下函数才会返回true,否则返回false,也就是要求,不仅值相等,并且类型也必须相等,看下面代码:

public class Example
{
   public static void Main()
   {
      byte value1 = 12;
      int value2 = 12;

      object object1 = value1;
      object object2 = value2;

      Console.WriteLine("{0} ({1}) = {2} ({3}): {4}",
                        object1, object1.GetType().Name,
                        object2, object2.GetType().Name,
                        object1.Equals(object2));
   }
}
// The example displays the following output: 
//        12 (Byte) = 12 (Int32): False

int != byte 所以两者值虽然相等但仍然返回false

同时C#中struct类型也是值类型的,所以,如果Box是个struct,那么情况又不会不一样的,就会直接按值进行比较啦,看代码吧!

public struct Person
{
   private string personName;

   public Person(string name)
   {
      this.personName = name;
   }

   public override string ToString()
   {
      return this.personName;
   }
}

public struct Example
{
   public static void Main()
   {
      Person person1 = new Person("John");
      Person person2 = new Person("John");

      Console.WriteLine("Calling Equals:"); 
      Console.WriteLine(person1.Equals(person2)); 

      Console.WriteLine("\nCasting to an Object and calling Equals:");
      Console.WriteLine(((object) person1).Equals((object) person2));  
   }
}
// The example displays the following output: 
//       Calling Equals: 
//       True 
//        
//       Casting to an Object and calling Equals: 
//       True
虽然person1跟person2,看起来像是引用的样子,但其本质是值类型,所以比较的是值,而不是引用。

4、了解了Equals的基本注意点,那么该怎么使用呢?

      最常用的做法是在自定义的类中重写该方法,这也是讲这么多的原因,重写该方法去判断该类应该以怎样的方式(取决于自己的实现)来实现该方法。如果不重写,那么该类在判断的时候就会默认调用object的Equals方法来比较两者的引用是否相等,而不会比较两者的内容是否相等。

public class Person
{
   private string idNumber;
   private string personName;

   public Person(string name, string id)
   {
      this.personName = name;
      this.idNumber = id;
   }

   public override bool Equals(Object obj)
   {
      Person personObj = obj as Person; 
      if (personObj == null)
         return false;
      else 
         return idNumber.Equals(personObj.idNumber);
   }

   public override int GetHashCode()
   {
      return this.idNumber.GetHashCode(); 
   }
}

public class Example
{
   public static void Main()
   {
      Person p1 = new Person("John", "63412895");
      Person p2 = new Person("Jack", "63412895");
      Console.WriteLine(p1.Equals(p2));
      Console.WriteLine(Object.Equals(p1, p2));
   }
}
// The example displays the following output: 
//       True 
//       True

可以看到,自己定义这个person类中,重写的时候规定了比较id,那么再调用时就调用自己的方法,而不会调用父类Object的方法去默认比较两者引用是否相等。

请注意前面的override关键字,也就是说这里的函数一定要跟Object类是完全一样的,包括参数类型也必须是Object。

这是一种实现方式,通过重写Object类的该函数,但是类型时Object,传参的时候都要类型转换,比较麻烦,有木有别的途径?有的,通过实现IEquatable这个接口,就可以了。

public class Person : IEquatable
{
public bool Equals(Person other) 
   {
      if (other == null) 
         return false;

      if (this.uniqueSsn == other.uniqueSsn)
         return true;
      else 
         return false;
   }
.......
}

总结一下自定义类实现Equals函数的两种形式:

  • 重写Object类
  • 实现接口IEquatable,写一个强类型的比较函数。

    

public bool Equals(Person other) 
   {
      if (other == null) 
         return false;

      if (this.uniqueSsn == other.uniqueSsn)
         return true;
      else 
         return false;
   }

   public override bool Equals(Object obj)
   {
      if (obj == null) 
         return false;

      Person personObj = obj as Person;
      if (personObj == null)
         return false;
      else    
         return Equals(personObj);   
   }   


   好了关于Equals的总结,就到这里了,还有更多的细节,请参考篇头的MSDN该函数的详细解释,不过本篇的拿下感觉已经够用了,毕竟我们不是专搞语言的,不必太深入了。

   鉴于篇幅原因,第二三个函数在(二)中再继续探讨。


    



你可能感兴趣的:(C#)