在定义数据结构时,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. Idea 破解教程 (2018.11-29最新版)

    一.下载安装idea,这里不做赘述.官网-https://www.jetbrains.com/idea/ 二.安装完idea后,需要激活使用.这里需要先下载个工具包 ,下载网址http://idea. ...

  2. 20145319 《网络渗透》免考—API拦截技术

    20145319 <网络渗透>免考-API拦截技术 概述 本次实验在window环境下进行,主要通过编写hook代码和注入程序,将我们的hook代码通过dll文件的形式注入到目标中,拦截其 ...

  3. 用C++调用tensorflow在python下训练好的模型(centos7)

    本文主要参考博客https://blog.csdn.net/luoyexuge/article/details/80399265 [1] bazel安装参考:https://blog.csdn.net ...

  4. bzoj 3522 / 4543 [POI 2014] Hotel - 动态规划 - 长链剖分

    题目传送门 bzoj 3522 需要root权限的传送点 bzoj 4543 快速的传送点 慢速的传送点 题目大意 给定一棵树,问有多少个无序三元组$(x, y, z)$使得这三个不同点在树上两两距离 ...

  5. Android灯光系统--通知灯深入分析【转】

    本文转自:https://www.cnblogs.com/lkq1220/p/6406261.html Android灯光系统--通知灯深入分析 通知的类别 声音 振动 闪灯 APP如何发出通知灯请求 ...

  6. centos6.8下源码编译安装tmux

    1. 获取源码 git clone https://github.com/tmux/tmux.git ~/tmux 2. 准备工作 2.1 安装ncurses开发库 yum install ncurs ...

  7. Win10子系统Ubuntu安装llvm+clang

    https://apt.llvm.org/ 首先 然后 再然后修改/etc/apt/sources.list,添加下面的东西 然后 参考: https://blog.kowalczyk.info/ar ...

  8. 给ThinkPad E470C 换个高分屏(1080P)

  9. UML类图中箭头的含义

    Explanation of the UML arrows Here's some explanations from the Visual Studio 2015 docs: UML Class D ...

  10. git删除远程分支文件,不改变本地文件

    git提交项目时候踩的Git的坑 特别 由于准备春招,所以希望各位看客方便的话,能去github上面帮我Star一下项目 https://github.com/Draymonders/Campus-S ...