在定义数据结构时,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详解的更多相关文章

  1. CSS中伪类及伪元素用法详解

    CSS中伪类及伪元素用法详解   伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的 ...

  2. java中ReentrantLock类的详细介绍(详解)

    博主如果看到请联系小白,小白记不清地址了 简介 ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字 ...

  3. java中Timer类的详细介绍(详解)

    一.概念 定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程的方式进行处理,所以它和多线程技术还是有非常大的关联的.在JDK中Timer类主要负责计划任务的功能,也就是在指定 ...

  4. java中ThreadLocal类的详细介绍(详解)

    ThreadLocal简介 变量值的共享可以使用public static的形式,所有线程都使用同一个变量,如果想实现每一个线程都有自己的共享变量该如何实现呢?JDK中的ThreadLocal类正是为 ...

  5. java中Calender类的详细用法(详解)

    一. 如何创建 Calendar 对象 Calendar 是一个抽象类, 无法通过直接实例化得到对象. 因此, Calendar 提供了一个方法 getInstance,来获得一个Calendar对象 ...

  6. java中Condition类的详细介绍(详解)

    已找不到原文了,还望原文博主看到能告诉小白一下,一定标注原文地址 一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait(). ...

  7. java中Dateformat类的详细使用(详解)

    DateFormat其本身是一个抽象类,SimpleDateFormat 类是DateFormat类的子类,一般情况下来讲DateFormat类很少会直接使用,而都使用SimpleDateFormat ...

  8. VBA中自定义类和事件的(伪)注册

    想了解一下VBA中自定义类和事件,以及注册事件处理程序的方法. 折腾了大半天,觉得这样的方式实在称不上“注册”,所以加一个“伪”字.纯粹是瞎试,原理也还没有摸透.先留着,有时间再接着摸. 做以下尝试: ...

  9. C#中自定义类数组和结构数组的使用

    如有雷同,不胜荣幸,若转载,请注明 C#中自定义类数组和结构数组的使用 最近在很多项目中发现很多时候给定的数组要实现某个逻辑或处理很是麻烦,一维数组,二维数组,,,等等需要经过n多转换,还不如自己写一 ...

随机推荐

  1. k8s build new API

    apiserver-builder git hub api conventions storage api arch step by step,   we can follow it. api con ...

  2. Overture 5入门之如何设置延音线

    延音线作为五线谱标记符合之一,是大家使用Overture时需要常用的一个基本标记符号.延音线是一条向上或向下弯曲的弧线,它的作用是将两个或两个以上的具有相同高音的音符来进行相连. 延音线作为再编曲演唱 ...

  3. Windows 登录用户的类型

    转载:http://blog.csdn.net/chenlycly/article/details/45419259 1.登录的是超级管理员Administrator 默认情况下,超级管理员Admin ...

  4. c和c++main函数的参数

    1.代码 int main(int argc,char **argv[]) { ; } 2.分析 argc:代码参数个数 argv:二级指针,很多个字符串,这里代表参数列表 3.分析 这个代码最终被编 ...

  5. topcoder srm 465 div1

    problem1 link 以两个点$p,q$为中心的两个正方形的边长和最大为$2dist(p,q)$,即$p,q$距离的两倍. 也就是两个$p,q$的连线垂直穿过两个正方形的一对边且平分两个正方形. ...

  6. 从0开始安装fedora23的笔记-- 以及使用fedora的常规问题

    关于安装过程中的笔记本 触摸板 和鼠标的问题? 在安装过程中, 系统只认从usb接口插入的鼠标和触摸板上的 "左键和右键"按钮. 触摸板上的鼠标只支持"移动"的 ...

  7. P4782 【模板】2-SAT 问题

    https://www.luogu.org/problemnew/show/P4782 链接 https://www.luogu.org/problemnew/show/P4782 思路 选a就必须选 ...

  8. 题解——Codeforces Round #508 (Div. 2) T1 (模拟)

    依照题意暴力模拟即可A掉 #include <cstdio> #include <algorithm> #include <cstring> #include &l ...

  9. Transaction2

    5. 事务状态 TransactionInformation 上面讲解过事务分为本地事务与分布式事务,而Transaction类的TransactionInformation是事务状态的记录,它可以跟 ...

  10. Entity Framework Core

    Entity Framework是一种支持 .NET 开发人员使用 .NET 对象处理数据库的对象关系映射程序 (O/RM). 它不要求提供开发人员通常需要编写的大部分数据访问代码. Entity F ...