C#常用容器源码分析

Posted by JohnWayne on April 25, 2022

泛型支持多类型,但需要指定类型,不用转换类型,不用装箱/拆箱操作,效率更高,使用范围广。


C# 官方源码地址 https://referencesource.microsoft.com/

C# 官方文档地址 https://docs.microsoft.com/en-us/dotnet/api/?view=netframework-4.8

根据源码的接口派生关系,可得到UML图

Array

ArrayList

存储结构是array

List

存储结构是array,比ArrayList多了泛化

HashTable

存储结构为bucket结构体,包含key,value和hash_coll

Dictionary<Tkey, TValue>

存储结构比HashTable多一个next字段,和python3.6之后的字典多了indices一样,为了有序

用一段代码验证一下猜想

using System; 
using System.Collections;
using System.Collections.Generic; 
  
class Test { 
    public static void Main() 
    { 
  
        Hashtable ht1 = new Hashtable(); 
  
        ht1.Add(3,"C"); 
        ht1.Add(2,"B"); 
        ht1.Add(1,"A"); 
        foreach(var v in ht1.Values)
        {
            Console.WriteLine(v); 
        }
        Dictionary<int,string> dict1 = new Dictionary<int,string>();
        dict1.Add(3,"C");  
        dict1.Add(2,"B");  
        dict1.Add(1,"A"); 
        foreach(var k in dict1)
        {
            Console.WriteLine(k); 
        }
    } 
}
>>>
A
B
C
[3, C]
[2, B]
[1, A]

果然Dictionary是按顺序添加的,HashTable则不保证先后顺序

LinkedList

储存结构是LinkedListNode

Stack

存储结构是array,当容量小于90%时会换个小的数组(手动调用TrimExcess,好像不会自动调用),push时容量满了会2倍扩容

Queue

和stack不同的是,_head 和 _tail的更新需要加1和数组长度取模,这样做的好处是在出队后再入队的情况下节省空间,不用一直扩容

HashSet

存储结构是m_buckets和m_slot,桶数组存相同hash指,slot存放hash映射的值,当冲突时通过next把元素串起来,是链地址法。

作者 [张巍]

2022 年 04月 25日