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

来源:互联网 发布:怎么下载淘宝网 编辑:程序博客网 时间:2024/06/06 00:36


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

上一篇详细搞了Equals,这一篇重点说下GetHashCode函数有什么用,怎么用,在哪里用,用的时候注意什么。

然后简要说下ToString的意义所在,因为比较简单,就不详细说明了。


1、GetHashCode函数有什么用?


依然参考官网的一句话来解释,“A hash code is a numeric value that is used to insert and identify an object in a hash-based collection such as the Dictionary<TKey, TValue> class”,大意就是说,HashCode就是来确定一个对象的唯一值,被用来当做那些运用了hash查找的容器或者函数来进行插入或者唯一的确定查找。

更通俗的讲,就是,一个对象,当把这个对象添加到一个键值对这样的容器(如Dictionary<Key,Value>)时,可以调用该对象的这个函数来得到一个唯一的HashCode(相当于一个对象的整数ID),把该值放入键值对容器中作为唯一的键值,可以进行查找,插入操作。


再具体点讲,就是,当我们放入两个相同的对象如 string s1 = “aaa” ;string s2 = "aaa";,s1,s2放入Dictionary中时,我们知道Dictionary是不允许Key值相等的,那么s1,s2,放入其中,他们的key时多少?如何得到这个key?对的,这个时候,GetHashCode函数就派上用场了,这个Dictionary就会调用这两个对象的GetHashCode函数来得到两个HashCode值,其实GetHashCode就是一个hash函数,把对象映射成唯一的一个对象ID,便于我们在把对象放入利用了hash映射的容器时,这些容器能得到每个对象的hash值,别的地方还真用不上呢。


2、这个函数是怎么工作的?


因为每个类的父类都是Object类,所以定义的每个类中都默认有个继承的方法GetHashCode,当然你完全可以重写它。(有些时候还必须重写,这正是本文重点说明的地方,因为默认的父类hashCode的值,是基于父类的引用值)

其实就是一hash函数,来产生一个值,然后返回,作为这个对象唯一的一个Id。


3、怎么用?


通常只需要在对象中重写就行了,但是要注意的是,该值一定要确保唯一,不要发生重复。如果重复的结果就是两个不同的对象对应了同一个相同的Id(hashcode),这显然不是我们想要的。

  public override int GetHashCode()    {         return Tuple.Create(x, y).GetHashCode();    } 

Tuple是一个序列化数组,创建x,y,序列数组,这是官网提供的一种hash映射方式,当然你可以发挥想象尽可能的确保x与y的计算组合值一定时,x与y也相同,因为我们要保证hashcode一样,那么两个类也相同,同时也引出了下一条注意事项就是,重写了hashcode这个函数,也一定要重写Equals这个函数,并且确保hash值也是一样的,不然相同的类对应不同的hashcode,多蛋疼啊。

If you override the GetHashCode method, you should also override Equals, and vice versa. If your overridden Equals method returns true when two objects are tested for equality, your overriddenGetHashCode method must return the same value for the two objects.

If an object that is used as a key in a hash table does not provide a useful implementation of GetHashCode, you can specify a hash code provider by supplying an IEqualityComparer implementation to one of the overloads of the Hashtable class constructor。


官网的解释是:要保证两个相等的对象有唯一的一个hashcode值,(这当然是必须的啊!)保持语义的一致性。

所以一个完整的应该是:

public class DaichoKey : IEquatable<DaichoKey>{    public int ID { get; set; }    public int SubID { get; set; }     public bool Equals(DaichoKey other)    {        return this.ID == other.ID && this.SubID == other.SubID;    }    public override bool Equals(object obj)    {        if (obj == null) return base.Equals(obj);         if (obj is DaichoKey)            return Equals(obj as DaichoKey);        else            throw new InvalidCastException("the 'obj' Argument is not a DaichoKey object");    }    public override int GetHashCode()    {        return base.GetHashCode();//return object's hashcode    }}



另外要说的是,不仅仅是Dictionary这类容器,才需要重写该函数,更重要的是,凡是要利用类的hashcode来作为key值来进行查找的函数都要重写,譬如说List,虽然是个线性表,但是它的函数Contains,IndexOf函数,都是利用类的hashcode值,来hash映射查找的,所以如果要加入List的中类,没有实现GetHashCode函数,它调用Contains和IndexOf函数时,相同的类对象,但它会找不到的。更为细节的讨论,请看专题你要小心的GetHashCode这篇文章有详细的解释。

4、ToString作用?

就是不想干巴巴的得到一个类的名字,当想把一个类的各个属性值都取得并用于打印或者其他用途是,返回一个类的字符串比返回一个类的引用值要有用的多。



0 0
原创粉丝点击