ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

16-02-C#常用数据结构源码-附录B-源码索引速查

16-02-C#常用数据结构源码-附录B-源码索引速查 附录 B源码索引速查系列C# 与常用数据结构源码剖析 · 附录基线主体集合以dotnet/runtimetag v8.0.0commit 5535e31a712343a63f5d7d796cd874e563e5ac14为研究基线泛型OrderedDictionaryTKey,TValue以 v9.0.0commit 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3为基线。目录和私有 helper 可随版本变化使用时先 checkout tag再用rg搜索类型/方法。一、先锁定版本git clone https://github.com/dotnet/runtime.git cd runtime git fetch --tags git checkout v8.0.0 git rev-parse HEAD # 5535e31a712343a63f5d7d796cd874e563e5ac14 # 研究 .NET 9 泛型 OrderedDictionary 时使用独立 worktree避免混淆文件 git worktree add ../runtime-v9 v9.0.0 # runtime-v9 HEAD: 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3一篇可复核的源码分析至少记录仓库 URL、tag、git rev-parse HEAD、文件路径、目标 TFM、SDK/runtime 完整版本和架构。若 tag 与实际部署 patch 不同应换成对应 servicing tag/commit而不用main猜测。二、System.Private.CoreLib 核心集合v8.0.0主题可检索入口相对dotnet/runtime建议搜索Array公共 APIsrc/libraries/System.Private.CoreLib/src/System/Array.csCopy、Clear、BinarySearch、Sort数组泛型接口辅助src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.csSZArrayHelper、IListT、GetEnumeratorListTsrc/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs_items、AddWithResize、RemoveAll、EnumeratorLinkedListTsrc/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cshead、InternalInsertNodeBefore、InternalRemoveNode、InvalidateDictionaryTKey,TValuesrc/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.csEntry、TryInsert、FindValue、Resize、StartOfFreeListHashSetTsrc/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.csFindItemIndex、AddIfNotPresent、IntersectWith、CheckUniqueAndUnfoundElementsQueueTsrc/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs_head、_tail、MoveNext、SetCapacityStackTsrc/libraries/System.Collections/src/System/Collections/Generic/Stack.csPushWithResize、Pop、TryPop、EnumeratorPriorityQueueTElement,TPrioritysrc/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.csArity、MoveUp、MoveDown、EnqueueDequeueSortedSetTsrc/libraries/System.Collections/src/System/Collections/Generic/SortedSet.csAddIfNotPresent、Remove、InsertionBalance、TreeSubSetSortedDictionaryTKey,TValuesrc/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.csTreeSet、KeyValuePairComparer、KeyCollectionSortedListTKey,TValuesrc/libraries/System.Collections/src/System/Collections/Generic/SortedList.cskeys、values、Array.BinarySearch、InsertSpanTsrc/libraries/System.Private.CoreLib/src/System/Span.csSlice、GetPinnableReference、EnumeratorMemoryTsrc/libraries/System.Private.CoreLib/src/System/Memory.csSpan、Slice、PinArrayPoolT抽象src/libraries/System.Private.CoreLib/src/System/Buffers/ArrayPool.csShared、Rent、Return、Create共享数组池实现src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.csRent、Return、线程本地槽、修剪Array.Copy、数组分配、JIT intrinsic 或 GC 写屏障的完整路径可跨越托管层与 CoreCLR VM/JIT/GC。从Array.cs开始根据目标 tag 中的[Intrinsic]、[InternalCall]、QCall/FCall 标记或 JIT 识别点继续搜索不用一段旧 C 伪码代表全链路。三、并发与不可变集合v8.0.0主题可检索入口建议搜索ConcurrentDictionaryTKey,TValuesrc/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.csTables、TryAddInternal、GrowTable、AcquireAllLocksConcurrentQueueT外壳src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs_head、_tail、Enqueue、TryDequeue、快照协调ConcurrentQueueSegmentTsrc/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.csSlot、SequenceNumber、TryEnqueue、TryDequeue、EnsureFrozenForEnqueuesConcurrentStackTsrc/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.csPushCore、TryPopCore、NodeConcurrentBagTsrc/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.csWorkStealingQueue、LocalPush、TryStealBlockingCollectionTsrc/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.csIProducerConsumerCollection、CompleteAdding、TakeFromAnyImmutableArrayTsrc/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.csBuilder、ToImmutable、InterlockedImmutableListTsrc/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.csNode、Balance、BuilderImmutableDictionaryTKey,TValuesrc/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.csHashBucket、MutationInput、BuilderImmutableHashSetTsrc/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.csHashBucket、MutationInput、Builder、Union某些文件在不同 tag 中可在System.Private.CoreLib与独立 library 之间调整。路径不存在时使用rg --files src/libraries | rg /ConcurrentQueue\.cs$或搜索类声明不为了保持附录文字而强行应用错路径。四、.NET 9 泛型 OrderedDictionary主题v9.0.0检索方法边界System.Collections.Generic.OrderedDictionaryTKey,TValuesrc/libraries/System.Collections/src/System/Collections/Generic/OrderedDictionary.cs使用 .NET 9 reference assembly 确认 GA API再用v9.0.0解释顺序存储与 key 索引的私有实现。旧非泛型OrderedDictionarysrc/libraries/System.Collections.Specialized/src/System/Collections/Specialized/OrderedDictionary.csnamespace、API、装箱和实现均不同不能与 .NET 9 泛型类型混用证据。IAlternateEqualityComparerTAlternate,T与 Dictionary alternate lookup 属于后续框架/API 演进主题。本索引不将它标为 .NET 6 或 .NET 8 的普遍公共契约研究时必须用目标 reference assembly 编译并锁定对应 runtime tag。五、CoreCLR、Mono 与设计文档主题目录/检索入口RyuJITsrc/coreclr/jit/从compiler.h、importer、morph、VN、lowering、codegen 相关文件与jit-diff工具入手CoreCLR GCsrc/coreclr/gc/搜索gc.cpp、gcpriv.h、heap/segment/generation/pinning 等符号CoreCLR VM/类型系统src/coreclr/vm/搜索MethodTable、EEType、array、generic dictionary、dispatch 等主题Monosrc/mono/按 runtime、metadata、mini/JIT、interpreter 与 GC 具体主题搜索ReadyToRun / crossgen2src/coreclr/tools/aot/crossgen2/结合目标 tag 搜索 compilation、dependency graph、R2R emission 与命令行入口NativeAOTsrc/coreclr/nativeaot/ 与 src/coreclr/tools/aot/按 compiler、runtime、ILCompiler、object writer 等目标主题搜索原生宿主src/native/corehost/搜索 hostfxr、hostpolicy、runtimeconfig、deps 与框架解析CoreCLR BOTRdocs/design/coreclr/botr/用于建立概念图再与目标 tag 源码相互校验库设计文档docs/design/libraries/ 与src/libraries/*/README.md目录随 tag 变化用rg --files docs查找SOH/LOH/POH 的 segment、压缩、修剪和内存压力策略必须从指定 GC 版本、配置、架构和实验解释。本附录不列“.NET 8 LOH 分段优化”这类没有已锁定 PR、测试和运行时证据的笼统变更。六、Roslyn 与 Unity 源码边界Roslyn 不在dotnet/runtime仓库。使用dotnet/roslyn根据 SDK 中Microsoft.CodeAnalysis*.dll的版本/commit 信息 checkout 对应源码然后从以下入口搜索主题可检索入口相对dotnet/roslynC# Syntaxsrc/Compilers/CSharp/Portable/Syntax/及Syntax/InternalSyntax/Binder / Symbolssrc/Compilers/CSharp/Portable/Binder/、Symbols/Bound Tree / Loweringsrc/Compilers/CSharp/Portable/BoundTree/、Lowering/具体文件按 commit 搜索Emit / PDBsrc/Compilers/Core/Portable/Emit/与 C# Emit 相关目录Analyzer / Generator APIsrc/Compilers/Core/Portable/DiagnosticAnalyzer/、SourceGeneration/及 SDK 公开 API 测试Unity 的 Mono/IL2CPP/Burst/Collections 版本与引擎发行绑定。桌面dotnet/runtime v8.0.0可用作算法参考不可作为 Unity 私有字段、GC、JIT/AOT 或 API 可用性的直接证据。必须记录 Unity Editor 完整版本、包版本、API Compatibility Level、脚本后端和目标 Player。七、从“我想知道什么”到“证据在哪里”源码索引只解决入口问题。真正的源码研究应从一个可观察问题出发而不是从“打开一个很长的文件”出发。例如“Dictionary.Remove之后为什么不立即缩容”是可以用公开行为、字段不变式和分配实验共同回答的问题“Dictionary 内部怎么写”则太宽容易变成字段抄录。7.1 先判定证据层级同一句结论可能需要四种完全不同的证据问题首要证据不能单独作为证据的材料某 TFM 能否调用成员reference assembly、API 文档、实际编译main分支已有该方法公开行为是什么文档、规范、公开测试与黑盒实验某个私有 helper 的名字固定版本如何实现tag/commit 下的源码、测试和构建产物另一版本的博客截图性能为何如此固定环境的 trace、反汇编、分配与基准源码看起来“只有几行”这个分层可避免两类常见错位用私有实现猜 API 契约或用 API 契约猜私有布局。前者会让应用依赖随时可变的细节后者则会把不同运行时强行画成同一张图。7.2 一条可复用的追踪链研究一个集合操作时可按以下顺序前进写出公开语义先记录返回值、异常、顺序、线程安全和枚举失效规则暂时不看字段。找公开入口在类声明中定位成员注意同名重载、显式接口实现和部分类文件。画调用小图只记录与问题有关的 helper、快路、慢路和异常边不复制整个调用树。提取不变式对比操作前后的Count、容量、链接、版本号、owner 与可达性说明每个写入为何必要。读同 tag 测试搜索类名、成员名、异常类型和边界值。测试常比注释更清楚地表明作者要守住什么。用最小程序封闭回路黑盒断言公开行为如果研究性能再增加分配、事件、JIT 证据或 heap snapshot。只有第 2‑4 步属于“读实现”。第 1、5、6 步让结论可以被外部观察和反例检验否则很容易把一段可读的伪代码当成事实。7.3 搜索时不要只搜类名类名适合找入口控制流和不变式往往要搜其他线索。查异常路径时搜异常资源或 throw helper查枚举失效时搜_version的所有写入查清引用时搜IsReferenceOrContainsReferences、Clear和default查并发发布时搜Volatile、Interlocked、lock以及不变表的整体替换。还应搜对应测试中的极端输入如空集合、自身作为参数、比较器冲突、枚举期修改和容量上限。八、四个典型追踪案例8.1 Dictionary 删除一次操作同时改两条链从Remove入口开始先找它如何用哈希和 comparer 定位桶再记录当前节点和前驱节点。命中后不只是“把 key/value 清空”桶内冲突链需要越过被删槽位而被删槽位又要编码进 free list。此时_count仍可以是已启用区间上界公开Count则要结合_freeCount理解。验证不应反射断言某个负数常量永久不变。更稳定的做法是使用恒定哈希 comparer 构造长冲突链删除链头、中间和链尾分别断言其他键仍可查找再插入新键用分配或容量观察证明槽位能复用。这样即使下一版改变 free list 的具体编码测试仍能守住算法目的。8.2 ConcurrentQueue外层段链与段内协议要分开先读ConcurrentQueue.cs中头尾段、新段链接和快照协调再进入ConcurrentQueueSegment.cs读槽位序号、head/tail 票号与环形映射。如果只读外层会看到“取当前尾段并尝试入队”却无法证明两个生产者为什么不会同时发布同一槽位。如果只读段内又会漏掉段冻结、增长和旧段保活。这个案例还说明“成功出队会清引用”为什么不能写成无条件句子。快照式枚举或TryPeek为了保持可观察内容可使某些段暂时保留 item。正确的实验是分开验证 FIFO/不丢不重的功能压力测试与对象保活的 heap 实验不用一张堆快照反推无锁正确性。8.3 ImmutableList追踪“哪些节点没有变”持久化集合的阅读重点不是数了多少个new Node而是标出修改路径和未访问子树。对SetItem、Insert或RemoveAt选一个操作沿索引导航到目标记录返回新根时哪些祖先被重建、哪些左右子树引用被原样复用。如果平衡因子越界再只展开局部旋转不要把旋转误写成整树拷贝。Builder 需要另走一条证据链。它能否原地改写取决于节点是否由当前构建阶段独占而不是“Builder 返回可变 List”。实验时保留几个旧快照对 Builder 执行批量修改并发布新版最后再断言所有旧版内容未变。这比反射查_frozen值更接近应用真正依赖的契约。8.4 Array.Copy托管入口不是执行链终点先在Array.cs找公开入口和参数检查再看固定 tag 中的 intrinsic、internal call 或运行时识别点。不同元素形状可走不同路径纯字节搬运、引用复制需要 GC 协议数组协变还可能需要赋值兼容检查。只看 C# 入口的方法长度无法推导最终复制指令、屏障成本或重叠区域语义。验证时至少分开纯值类型、引用类型、含引用字段的值类型和可能触发协变检查的数组。功能测试覆盖同数组重叠拷贝与边界性能测试再固定长度、架构、GC 和运行时版本。这样才能解释“语义相同的 Copy”为何对不同T表现出不同实现成本。九、源码阅读中的十个常见误读把文件路径当 API 契约类可以跨 partial 文件、平台特定文件和生成代码文件搬家不等于公开行为改变。把方法名当实际调用次数JIT 可内联helper 又可分出快慢路一个源码调用点不对应固定机器间接次数。把私有字段当序列化格式存档、网络和签名协议必须由显式 DTO 与规范定义不能跟随_entries或枚举顺序。用main证明旧发行版main可含尚未发布的 API、已回退的实验或新平台文件。历史结论必须回到 tag/commit。用 tag 名代替部署版本v8.0.0适合统一教学基线却不自动等于生产机的 servicing patch。调查故障时要对齐实际 runtime commit。只看正常路径比较器抛异常、容量溢出、自身集合运算、取消和竞争失败才常是不变式被真正考验的地方。把结构化节选当可替换源码教学片段常删除 null 检查、溢出、架构分支与异常恢复只能用于说明主干。看到 lock 就否定“无锁快路”进度保证要精确到操作。单元素快路可为 lock-free快照、扩容或全局观察仍可使用锁。用源码行数排性能分支可被折叠小方法可内联一行 intrinsic 可进入大量运行时代码。成本必须由最终执行路径和数据分布解释。把桌面 CoreCLR 路径移植到 Unity即使类名相同Unity 的类库代际、Mono fork、IL2CPP 转换和 GC 也可不同共用业务库要只依赖共同公开契约。十、版本升级时如何复核从 .NET 8 升到新 runtime 时不应用“文件还在、所以结论不变”作为审查。一次高效复核可分五层10.1 API 与参考程序集先编译项目实际使用的成员检查新增、过时、可空注解、泛型约束和重载决议。这一层回答“代码能不能以相同语义编译”与私有算法 diff 分开。10.2 符号级 diff而不是逐行噪声在旧新 tag 中先按类和方法列出关注符号再对这些符号的字段读写、调用 helper 和测试集做差异。大量格式化、命名和文件搬迁可以先排除。重点记录不变式是否改变例如容量选择、冲突处理、版本号更新、空闲槽位表示、快照协议和并发发布顺序。10.3 实现测试与业务回归运行新 tag 对应的上游测试但不要把上游测试当作业务协议的替代品。项目仍要覆盖自己的 comparer、序列化、并发拓扑、容量峰值、Unity Player 和 AOT/裁剪路径。上游测试证明维护者想守住的实现行为业务回归证明你的依赖没有被破坏。10.4 性能重建基线将旧新 runtime 放在同一硬件和发布配置下固定数据集、预热、PGO/R2R、GC 和采样方式。同时保存正确性校验和原始报告不只保存 Ratio。如果结果改变先用分配、代码版本、分支与缓存证据定位再将它归因于某个源码 diff。10.5 更新结论的表述范围最终记录三类结果公开契约是否改变私有实现是否改变项目实测是否改变。只有第一类适合直接写成跨实现依赖第二类必须继续携带 tag/commit第三类必须携带环境和输入。“升级后快了”不是完整结论“在某负载下某代码版本的分配或分支改变”才是可继续复核的记录。十一、练习把索引变成可验证结论List 容量练习追踪Add、AddRange、EnsureCapacity与TrimExcess写出Count/Capacity不变式用空集合、已知ICollectionT、未知长度枚举和自身追加做差分测试。Dictionary 冲突练习不反射私有数组用可计数 comparer 统计成功/失败查找的Equals次数解释冲突链增长与比较成本的关系。Queue 环绕练习构造 head 不为零且有效区间跨数组末尾的状态验证ToArray、枚举和扩容仍保持 FIFO 逻辑顺序。ConcurrentQueue 观察练习在生产/消费并发压力中长时间持有一个枚举器比较持有前后的对象保活不将保活现象误判为 FIFO 错误。ImmutableList 旧版练习保存随机旧版连续执行插入、删除和替换每一步与普通ListT参考模型对比并在最后重新验证所有旧版。Array.Copy 路径练习对字节、引用和含引用结构分别测试重叠拷贝与大数组拷贝区分语义测试、分配事件和最终机器码证据。跨版本练习选一个容器在两个发行 tag 中做符号级 diff产出一页报告契约变化、实现变化、测试变化、项目是否受影响。Unity 边界练习选一个桌面 .NET 源码结论列出将它用于 Unity Player 前必须补齐的 Editor、BCL、Mono/IL2CPP、平台、构建和 Profiler 证据不直接复制桌面性能数字。完成练习的标准不是“找到了某个私有字段”而是能用一句有范围的结论连接契约、固定版本实现和可重复实验并能说明哪个反例会推翻它。上一篇附录 A术语表下一篇附录 C参考资源
返回列表