(转).Net中自定义类作为Dictionary的key详解
在定义数据结构时,Dictionary提供了快速查找数据的功能,另外Dictionary< TKey, TValue >属于key-value键值对数据结构,提供了泛型的灵活性,是数据结构的一个利器,但是目前拥有的string,int,bool等基础数据类型并不能满足我们的需求,那么如何把自定义的数据类作为Dictionary的key呢?
本文对Dict的内部实现会有提出,但不详细讨论,以解决标题问题为主,如果有想详细了解Dictionary内部实现等更多细节,请转到官网: 
https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx
首先需要搞清楚以下问题
- Dictionary是如何通过key找到的value?
 - 需要怎么做才可以让Dictionary认同我们的自定义类作为Key?
 - 具体代码应该怎么写,去实现?
 
一、Dictionary是如何通过key找到的value?
首先提几个简单的概念,对我们理解Dictionary有很大的帮助。
哈希表
定义:是一种用于描述有联系键值对数据结构的表。  
.NET中有Hashtable的类型,它是一个通过关键字直接访问内存存储位置的数据结构。Dict使用了它,也就是说,Dictionary内部的key,value的存放与查找其实都是由固定的内存地址的,但是数据量多了难免会出现多个key或者value拥有同样的内存地址,这样我们再通过寻址操作数据时就会出现冲突的问题,这个我们叫碰撞冲突。
Dict解决碰撞冲突的方案
Dict采用分离链接法,什么意思呢?就是当不同value被分配到同一个地址时,Dict会在那个地址下再建一个链接,用于存放不同value,放张图大家应该就知道是怎么回事了。 
明白了以上两个概念,我们基本上就可以理解这句话了: 
Dict判断查找key时,首先会调用GetHashCode方法,来取得key的Hashtable,判断Hashtable是否一致,如果Hashtable一样还不算找到,还需要继续判断存放的value是不是(相等)Equal,两个条件都满足,才算真正找到了我们需要的key,然后取出Dictionary存放的value值。
二、需要怎么做才可以让Dictionary认同我们的自定义类作为Key?
举一个栗子:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test_Dict
{
    class Program
    {
        class MyClass
        {
            private int ID { get; set; }
            private string name { get; set; }
            public MyClass(int ID, string name)
            {
                this.ID = ID;
                this.name = name;
            }
        } 
        static void Main(string[] args)
        {
            MyClass class_one = new MyClass(100,"nini_boom");
            MyClass class_two = new MyClass(200,"liyang");
            MyClass class_three = new MyClass(100, "nini_boom");
            Dictionary<MyClass, int> _TestDict = new Dictionary<MyClass, int>();
            _TestDict.Add(class_one,1);
            _TestDict.Add(class_two,2);
            Console.WriteLine(_TestDict.ContainsKey(class_three));
            Console.ReadKey();
        }
    }
}
可以看出,即使我们的class_three和class_one在内容上完全相等,但是Dict中仍然找不到。为什么呢?
因为Dict认为的key相等和我们认为的相等不一样 
为什么Dict不认为相等呢?我们知道,.Net中所有的数据结构都是继承了object,但是object本身对继承了它的数据一无所知,所以为了防止继承了objece的数据发生碰撞冲突现象,所以object的做法是让每一个继承它的数据的Hashtable都尽量不一样,因为我们的MyClass也是继承了object的,所以Dict在比较Class_one与class_three 的Hashtable时就认为他俩不相等,所以找不到。
为了实现在内容上相等的类,就可以寻找到同样内容的Key,也就是让自定义类作为Dictionary的key,我们需要重新定义一套比较的规定,来满足我们认为的相等
三、具体代码怎么写,去实现?
在Dict的内部实现中,比较两个key是否相等用到了两个方法:GetHashCode()和Equal(),所以接下来需要在自定义类中重写GetHashCode()和Equal()方法,分别得出Hashtable和比较规则,下次Dict再次比较时就会调用重写的GetHashCode和Equal来进行比较。 
再拿上面的栗子举下,增加两个方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test_Dict
{
    class Program
    {
        class MyClass
        {
            private int ID { get; set; }
            private string name { get; set; }
            public MyClass(int ID, string name)
            {
                this.ID = ID;
                this.name = name;
            }
            public override bool Equals(object obj)
            {
                var your_class = (MyClass)obj;
                return your_class.ID == this.ID && your_class.name == this.name;
            }
            public override int GetHashCode()
            {
                int id_hashcode = ID.GetHashCode();
                int name_hashcode = name.GetHashCode();
                return id_hashcode + name_hashcode;
            }
        } 
        static void Main(string[] args)
        {
            MyClass class_one = new MyClass(100,"nini_boom");
            MyClass class_two = new MyClass(200,"liyang");
            MyClass class_three = new MyClass(100, "nini_boom");
            Dictionary<MyClass, int> _TestDict = new Dictionary<MyClass, int>();
            _TestDict.Add(class_one,1);
            _TestDict.Add(class_two,2);
            Console.WriteLine(_TestDict.ContainsKey(class_three));
            Console.ReadKey();
        }
    }
}
这次返回的就是True了。
文章转载自:https://blog.csdn.net/nini_boom/article/details/78728129
(转).Net中自定义类作为Dictionary的key详解的更多相关文章
- CSS中伪类及伪元素用法详解
		
CSS中伪类及伪元素用法详解 伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的 ...
 - java中ReentrantLock类的详细介绍(详解)
		
博主如果看到请联系小白,小白记不清地址了 简介 ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字 ...
 - java中Timer类的详细介绍(详解)
		
一.概念 定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程的方式进行处理,所以它和多线程技术还是有非常大的关联的.在JDK中Timer类主要负责计划任务的功能,也就是在指定 ...
 - java中ThreadLocal类的详细介绍(详解)
		
ThreadLocal简介 变量值的共享可以使用public static的形式,所有线程都使用同一个变量,如果想实现每一个线程都有自己的共享变量该如何实现呢?JDK中的ThreadLocal类正是为 ...
 - java中Calender类的详细用法(详解)
		
一. 如何创建 Calendar 对象 Calendar 是一个抽象类, 无法通过直接实例化得到对象. 因此, Calendar 提供了一个方法 getInstance,来获得一个Calendar对象 ...
 - java中Condition类的详细介绍(详解)
		
已找不到原文了,还望原文博主看到能告诉小白一下,一定标注原文地址 一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait(). ...
 - java中Dateformat类的详细使用(详解)
		
DateFormat其本身是一个抽象类,SimpleDateFormat 类是DateFormat类的子类,一般情况下来讲DateFormat类很少会直接使用,而都使用SimpleDateFormat ...
 - VBA中自定义类和事件的(伪)注册
		
想了解一下VBA中自定义类和事件,以及注册事件处理程序的方法. 折腾了大半天,觉得这样的方式实在称不上“注册”,所以加一个“伪”字.纯粹是瞎试,原理也还没有摸透.先留着,有时间再接着摸. 做以下尝试: ...
 - C#中自定义类数组和结构数组的使用
		
如有雷同,不胜荣幸,若转载,请注明 C#中自定义类数组和结构数组的使用 最近在很多项目中发现很多时候给定的数组要实现某个逻辑或处理很是麻烦,一维数组,二维数组,,,等等需要经过n多转换,还不如自己写一 ...
 
随机推荐
- 13: vue项目结构搭建与开发
			
vue其他篇 01: vue.js安装 02: vue.js常用指令 03: vuejs 事件.模板.过滤器 目录: 1.1 初始化项目 1.2 配置API接口,模拟后台数据 1.3 项目整体结构化开 ...
 - Atlas读写分离[高可用]
			
Atlas下载地址: https://github.com/Qihoo360/Atlas/releases Atlas是出于360的, 比mysql-proxy更稳定, 部署起来更方便. 环境: pr ...
 - java常用类-StringBuffer,Integer,Character
			
* StringBuffer: * 线程安全的可变字符串. * * StringBuffer和String的区别? * 前者长度和内容可变,后者不可变. * 如果使用前者做字符串的拼接,不会浪费太多的 ...
 - 尚硅谷面试第一季-11MyBatis中当实体类中的属性名和表中的字段名不一样怎么办
			
问题: MyBatis中当实体类中的属性名和表中的字段名不一样 ,怎么办 ? 解决方案: 1.写sql语句时起别名 <!-- id属性:必须是接口中方法的方法名 resultType属性:必须是 ...
 - 【Python52--爬虫1】
			
一.Python如何访问互联网 采用urllib包来访问 二.理论 1.请问URL是“统一资源标识符”还是“统一资源定位符” URI是统一资源标识符,URL是统一资源定位符.即:URI是用字符串表示某 ...
 - 【学习】Hall’s Marriage Theorem
			
其实是在做题时遇到这个定理的. 这个定理的图论意义是: 对于一个二分图\(G=\{X+Y,E\}\),它满足: \(\forall W \subseteq X, \, |W| \leq |N_G(W) ...
 - FileAttributes Enum
			
https://docs.microsoft.com/en-us/dotnet/api/system.io.fileattributes?view=netframework-4.7.2 读取FileA ...
 - Ubuntu 更新系统版本以及查看当前系统版本的命令
			
1. Ubuntu 查看当前系统版本: lsb_release -a 2. Ubuntu 更新系统版本的命令: sudo do-release-upgrade
 - Cas单点登录配置数据查询用户
			
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
 - [转载]grep查看上下文及简单正则表达式
			
转载自:https://www.cnblogs.com/mfryf/p/3336288.html inux grep 显示前后几行的信息2016年03月02日 14:10:58 ChenHui246 ...