附录 C:参考资源
系列 :C# 与常用数据结构源码剖析 · 附录
统计口径 :截至 2026-08-14,
00---16共 17 个内容目录、90 个内容 Markdown 文件;另有根级Plan.md、文生关键词、质量审核记录以及验证说明/结果共 5 份支撑材料,故物理总数为 95。90 篇内容包含导览、篇章概要和附录,不表示 90 篇独立技术正文。链接访问日期 :2026-08-14。网站和
main分支会变化;本专栏的 .NET 8 源码基线固定为 dotnet/runtime@5535e31a712343a63f5d7d796cd874e563e5ac14,.NET 9 泛型OrderedDictionary基线固定为 dotnet/runtime@9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3。其他实现引用也应使用 commit permalink 并记录访问日期。
一、规范与官方 API 契约
- ECMA-335: Common Language Infrastructure --- CLI、CIL、CTS、元数据与虚执行系统的规范基础。
- C# language specification --- 语法、转换、重载解析、foreach、using、lock 等语义契约。
- C# language reference --- 面向开发者的语言参考。
- .NET API Browser --- 查询类型、成员、异常和目标框架可用性;注意选择正确版本。
- .NET collections --- 集合抽象与选型的官方入口。
- .NET fundamentals: target frameworks --- TFM 和目标 API 表面。
- .NET diagnostics documentation ---
dotnet-trace、dotnet-counters、dump 和运行时诊断入口。
规范回答语言/平台必须保证什么,API 文档/reference assembly 回答某 TFM 能调用什么。它们不代替私有实现源码或性能测量。
二、官方源码与设计资料
- dotnet/runtime --- .NET 类库、CoreCLR、Mono 和 NativeAOT 等源码。本专栏主线使用 v8.0.0 对应 commit 5535e31a712343a63f5d7d796cd874e563e5ac14;泛型
OrderedDictionary使用 v9.0.0 对应 commit 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3。 - dotnet/runtime release tags --- 查找发行和 servicing tag。引用时同时保存 commit SHA。
- Book of the Runtime(本专栏 v8 固定基线) --- CoreCLR 概念设计文档;需要当前演进状态时再访问
main,不要用浮动分支证明已发布 .NET 8 的实现。 - dotnet/roslyn --- C# / Visual Basic 编译器、语法/语义 API、Analyzer 与 Generator 基础设施。
- C# language design repository --- 语言提案和设计记录;proposal 不必等于最终已发布规范或实现。
- dotnet/BenchmarkDotNet --- BenchmarkDotNet 源码、文档和诊断器。
- microsoft/perfview --- PerfView 源码与发布包。
从 GitHub 网页复制源码链接时,优先使用包含 commit SHA 和行号的 permalink。不要用 blob/main/... 链接证明已发布 .NET 8 的字段或算法。参见 附录 B:源码索引速查。
三、Unity 官方资源
- Unity: .NET overview --- Unity 中的 .NET profile、运行时与兼容性入口。在文档页切换到项目对应 Editor 版本。
- Unity scripting backends --- Mono/IL2CPP 后端的官方说明。
- IL2CPP overview --- IL2CPP 构建管线与平台边界。
- Burst documentation --- Burst 支持、编译选项与诊断。
latest是浮动链接,项目文档应改用已安装包版本 URL。 - Unity Collections documentation --- NativeArray/NativeList/NativeHashMap 等容器契约。同样应固定包版本。
- Unity Profiler --- CPU、内存、GC 和 Player 连接分析。
- Unity Memory Profiler package --- 内存快照与可达性分析;请对齐实际包版本。
Unity 证据必须记录 Editor 完整版本、API Compatibility Level、包版本、Mono/IL2CPP、构建配置、目标设备和 Profiler capture。桌面 CoreCLR 源码或 Editor 运行结果不能替代目标 Player 证据。
四、实验、IL 与性能工具
- BenchmarkDotNet documentation --- .NET 微基准方法、jobs、diagnosers 和报告。
- SharpLab --- 快速观察 C#、IL 与 JIT 输出。请记录页面选择的编译器/运行时;在线结果不是项目目标环境的替代。
- ILSpy --- CLI 元数据、IL 和反编译 C# 工具。反编译 C# 是重建结果。
- dotnet-trace --- 运行时事件跟踪。
- dotnet-counters --- 运行时计数器监控。
- PerfView --- Windows ETW/TraceEvent、CPU 堆栈、GCStats 和堆分析。
- JetBrains dotMemory --- .NET 堆快照、支配树与引用分析。
- Visual Studio performance profiler --- CPU、内存、并发与运行时诊断。
工具结果必须与它的版本和配置一起解读。微基准回答特定局部问题,堆快照回答采集时刻的对象图,事件跟踪回答某段时间的行为;任何一种都不应被单独提升为无条件结论。
五、书籍与系统化阅读
- Jeffrey Richter, CLR via C#, 4th Edition --- .NET Framework 时代 CLR/C# 心智模型。具体私有实现需与现代 .NET 源码重新校验。
- Konrad Kokosa, Pro .NET Memory Management, 2nd Edition --- GC、分配、内存诊断与性能方法。
- Jon Skeet, C# in Depth, 4th Edition --- C# 语言特性、语义和演进。后续语言特性需补充官方规范/提案。
- Ben Watson, Writing High-Performance .NET Code, 2nd Edition --- .NET 性能设计与测量思路;版本性数字需重新实测。
- Maurice Herlihy and Nir Shavit, The Art of Multiprocessor Programming, 2nd Edition --- 线性化、无锁算法与并发正确性。
- Thomas H. Cormen et al., Introduction to Algorithms --- 复杂度、哈希、树、堆和均摊分析。
书籍建立长期模型,但无法代替当前 API 文档和发行 tag。引用某个固定数字、字段或平台差异时,需标明版次/页码,并在当前目标环境复核。
六、引用记录模板
主题:Dictionary<TKey,TValue>.TryInsert
契约:.NET API Browser / net8.0 reference assembly
源码:dotnet/runtime,tag v8.0.0,commit 5535e31a712343a63f5d7d796cd874e563e5ac14
路径:src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
永久链接:https://github.com/dotnet/runtime/blob/5535e31a712343a63f5d7d796cd874e563e5ac14/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
测试:同 tag 下对应单元测试路径
访问日期:2026-08-14
实验:SDK/runtime/OS/CPU/GC/输入分布/原始报告
这个模板强制分开契约、私有实现、测试和性能证据。一个 GitHub PR 能说明改动动机和 diff,却不自动证明已发布到某 SDK,也不自动证明在 Unity/IL2CPP 上有相同行为。
七、证据层级:先确定资料能回答什么
技术资料没有一个能够通吃所有问题的"最高权威"。规范对语义契约很强,却不说某版本 CoreCLR 的私有字段;源码能告诉我们某个 commit 如何实现,却不能单独证明另一个运行时或平台的实际性能。使用资料前要先把待证明的命题分类。
| 证据层 | 适合回答 | 不能单独回答 |
|---|---|---|
| 语言、CLI 与内存模型规范 | 程序必须遵守的语义、转换、可见性和元数据规则 | 私有布局、当前 JIT 代码形状、具体耗时 |
| reference assembly 与 API 文档 | 某 TFM 是否有类型、成员、重载、异常与公开契约 | 私有算法、实际内联、Unity 目标 Player 是否兼容 |
| 固定 commit 的实现源码 | 字段、辅助方法、算法分支和实现不变式 | 公开承诺、另一 tag 的行为、目标机器性能 |
| 同 tag 的单元测试 | 实现者重点保护的边界、异常、回归和平台差异 | 所有未覆盖行为、业务语义或性能上限 |
| 设计文档、issue 与 PR | 动机、替代方案、审查争议和改动时间线 | 最终发布状态、当前代码与客户端可观测结果 |
| 生成的 IL、机器码与跟踪 | 某个编译器、运行时、架构和输入下实际发生了什么 | 其他配置的普遍结论、长期稳定的 API 契约 |
| 可重复基准与业务回放 | 特定负载下的延迟、吞吐、分配、峰值与成本曲线 | 没有测量的输入分布、另一 CPU 或未来版本 |
| 技术书籍与二手文章 | 心智模型、历史背景、研究入口和关键词 | 需要精确 tag、API 或平台的最终证明 |
证据冲突时,不用"新资料一定胜旧资料"或"官方博客一定胜实验"粗暴裁决。先检查它们是否在回答同一问题:规范可能在说公开语义,源码在说某 commit 的实现,基准则在说某台机器的特定负载。如果确实冲突,记录版本、原始引文和实验条件,把冲突本身作为待验证问题,而不是悄悄删除不合预期的证据。
八、资料评估:七个问题比"是否官方"更有用
收录一份资料前,可用七个问题评估它。第一,主张是什么 :是 API 存在性、算法形状、性能数字,还是设计动机?第二,适用对象是什么 :语言、TFM、运行时、SDK、Unity Editor、包还是目标平台?第三,版本是否可定位:有没有 tag、commit、版次、发布日期或完整 Editor patch?
第四,证据是否直接 :资料是展示了代码、报告和原始数据,还是只引用另一篇摘要?第五,能否复现 :是否给出输入、环境、构建配置、预热、重复次数和结果校验?第六,边界是否明示 :作者是否把内部实现当成公开契约,把相关性当因果,或把一次快照当长期趋势?第七,能否被反驳:是否存在一种可观测结果会迫使主张修改?
高风险信号包括:不写版本却逐字展示私有字段;声称某容器"始终 O(1)"却不区分均摊、期望和最坏;只报一个快多少倍而没有功能校验;用 Editor 结果代表 IL2CPP 真机;用 main 分支解释已发布 tag;将 issue 中的设想当成已合并 API;只给截图而没有命令、报告和构建标识。这些信号不意味资料必然错,但意味着它只能做线索,不能直接成为教材结论。
可将评估结果写成一张"证据卡":一句原子主张、证据层、适用版本、原始链接或文献位置、能复现的最小步骤、已知反例、当前信心等级与待办验证。将"看过一篇文章"变成结构化记录,才能在半年后回答当时为什么相信它。
九、引用方法:一个引用只承载它真正支持的结论
可审查的引用从"原子主张"开始。不要用一个源码链接同时支撑"API 存在、这是公开承诺、它比另一方案快三倍"三件事。前两件事至少需要 reference assembly/API 契约与实现源码分别证明;性能主张还需要可重复实验。
契约类句子应写明目标版本,例如"在 net8.0 reference assembly 中,该成员的公开签名为......"。实现类句子应写"在 dotnet/runtime 的给定 commit 中可观察到......",避免把私有形状写成所有 .NET 的永久真理。性能类句子则需说"在以下环境与输入中观察到......",同时链接原始报告,不将结果扩展到未测平台。
引用源码时保存仓库、commit SHA、路径、类型/方法名与行号。行号是导航信息,commit 才是内容身份;后续文件增删行不应让旧引用漂到新逻辑。引用一段算法时只摘录论证所需的最小范围,并标注"逐字源码"、"结构化节选"还是"教学伪代码"。后两者不应伪装成仓库原文。
引用设计提案或 PR 时同时记录状态:草案、合并、回退、发布或仅在 preview。"PR 已合并"不等于"项目目标 TFM 已提供";合并后还要确认所在分支、首个发布 tag 与 reference assembly。引用书籍则记录版次、章节/页码和它面向的产品世代,不用现代 .NET 名词悄悄改写旧 CLR 的实现结论。
跨文章重用同一结论时,应引用同一张证据卡或固定来源,而不是将转述层层当成新证据。一处基线更新后,通过搜索 commit、API 名或证据卡 ID 定位所有消费者,能减少"总文已修正,面试篇仍保留旧说法"的内部矛盾。
十、Unity 版本固定:不用"Unity 6"代替实验坐标
Unity 的证据坐标比普通 net8.0 项目更长。至少记录 ProjectVersion.txt 中的完整 Editor 版本与修订标识、Build Target、OS/CPU 架构、Scripting Backend、API Compatibility Level、Managed Stripping Level、Development Build、Incremental GC、脚本定义符号、重要 Player Settings 与构建 commit。只写"Unity 2022"或"Unity 6"无法区分编译器、类库、IL2CPP、裁剪器和平台工具链的变化。
包版本不能只从文章的访问日期猜测。保存 Packages/manifest.json 与 lock 文件,记录 Burst、Collections、Entities、Memory Profiler、异步库、热更框架与源码生成器的确切版本。官方包文档的 latest 链接只用作发现入口;项目结论应换成对应已安装版本的文档页,并保存 manifest/lock 作为可审计事实。
编译证据、Editor 行为和 Player 行为要分开。一个最小探针应同时保留:编译器能否识别语法;reference assembly 是否有需要的类型和重载;Mono Editor/Player 是否执行通过;IL2CPP Player 在项目裁剪级别下是否保留反射成员与闭合泛型路径;真实设备上的线程、ABI、原生插件、异步续体和 Job 生命周期是否正确。语法通过不会自动证明后四层。
对性能资料,还要记录 Profiler 连接方式、Deep Profile、Safety Checks、Burst 开关、画质、帧率限制、温度和电源模式。Editor、Development Player 和 Non-Development Player 是三种不同的观测环境;Editor 适合定位,Development 适合获取详细证据,最终预算则应回到最低档目标设备与接近发布的配置。若平台不同时支持 Mono 与 IL2CPP,不能把两台不同设备的差异简化成后端差异。
十一、实验归档:让结论能在另一台机器上重建
一份可复现实验不只有结果表。最小归档包含六类产物:可从干净检出构建的源码与依赖锁定;创建输入和运行实验的脚本;完整环境清单;未经挑选的原始报告、trace、dump 或 capture;从原始数据生成表格的处理步骤;以及功能等价的 checksum、断言和回归测试。只保留一张柱状图,无法检查是否删掉了工作、改变了语义或隐藏了异常样本。
环境清单至少覆盖 OS 及补丁、CPU 型号/微码与架构、核数和频率策略、内存、SDK/runtime 完整版本、GC 模式、JIT/AOT/ReadyToRun/PGO、Release/Debug、进程位数、容器/虚拟化、工具版本和关键参数。数据结构实验再加元素类型与大小、容量、命中率、键分布、冲突率、读写比、初始容量、串并行度和随机种子。这些不是装饰元数据,而是结果的定义域。
原始产物应与解读分开。原始目录只追加、不手工修补;清洗脚本输出到新目录;文章表格记录从哪份原始数据与脚本生成。产物名可包含日期、commit 短 SHA、运行时、平台、场景和重复编号,但真实身份仍由 manifest 中的完整值确定。大文件无法进 Git 时,保存内容哈希、对象存储位置、保留期和访问权限,不要只在个人桌面留一份不可定位文件。
运行前定义排除条件,不要看完结果再删样本。例如设备进入热降频、背景更新占用 CPU、功能 checksum 错误、输入未完整消费或 Profiler 断开,都可以是事先声明的无效运行。有效运行应报样本数、分位数、离散程度和异常上下文,不用平均值掩盖双峰或慢尾。对比方案必须使用同一功能 oracle;如果一方不维持顺序、不处理失败或不包含构建成本,就要分开报告,不把不等价工作排名。
归档前要处理安全与隐私。dump、heap snapshot、trace 参数、路径、符号和测试输入可能包含凭据、玩家标识、请求内容或商业数据。脱敏应保留调查所需的结构,并记录修改过程;不得为了复现而将生产快照上传到公开仓库或第三方在线分析工具。
十二、失效链接与漂移结论的维护
链接可打开不表示证据仍有效。官方文档可能保留同一 URL 却默认切到新版本;GitHub main 可能完全改变文件;包文档的 latest 会指向新主版本;搜索结果的摘要可能来自旧缓存。因此维护同时检查"能否访问"和"现在内容是否仍支持原主张"。
将链接分为三类管理。第一类是可固定的证据,例如 commit permalink、发布 tag、规范版次和有版本的包文档,文章结论优先使用它们。第二类是浮动入口,例如 API Browser、项目主页和文档导航,用于发现新资料,不独立承载私有实现主张。第三类是外部二手资料,保留作者、标题、日期和必要摘要,并尽可能追溯它的一手来源。
可以在每次大版本升级、每次全专栏发布前和固定周期执行链接审计。自动检查负责 HTTP 状态、重定向、内部相对路径和锚点;手工检查负责版本选择、主张是否仍存在、页面是否已改为 preview 或新产品线。只有 200 OK 的检查会漏掉最危险的语义漂移。
发现失效时不默默换成"看起来相似"的新页面。先确认新来源支持同一主张和版本,再更新访问日期与证据卡。如果无法找到等价来源,将结论降级为待验证、删除过度精确的说法,或保留注释说明原证据已不可达。维护历史不是为了永久保留旧 URL,而是防止结论在换链接时悄悄改变。
十三、典型研究路线
13.1 查一个 API 在项目中是否可用
先写清项目的 TFM 或 Unity API Compatibility Level,再查 reference assembly 和官方 API 文档的版本选择。然后用最小项目直接编译准备使用的精确签名,不用 IDE 补全或另一台机器的 SDK 作证。若涉及 Unity,继续构建并启动目标 Player,尤其覆盖裁剪、AOT 泛型、反射和原生互操路径。最终结论是"在这个坐标中可用",不是"C# 支持"。
13.2 解释一个集合的私有实现
从公开契约列出不能被实现改动破坏的行为,再锁定运行时 tag 和 commit。按公开入口追踪到私有字段与核心方法,同时阅读同 tag 测试,用空集合、边界容量、重复、冲突、异常和枚举修改构建不变式。文章中将逐字源码、结构化节选和伪代码分别标记,并列出 Unity/旧 TFM 不能直接套用的边界。
13.3 验证一个性能主张
把"A 比 B 快"改写成包含操作、输入、语义、环境和指标的可反驳假设。先用正确性 oracle 保证两方完成同一工作,再用 profile/trace 证明该操作确实位于重要路径。微基准分离机制,业务回放验收系统影响;同时记录分配、常驻内存、峰值、慢尾和能耗等交换。结果保留曲线和原始报告,不只报最有利的一个参数点。
13.4 研究一次版本演进
先选择两个已发布端点,用 API diff 区分公开表面变化,再比较固定 commit 中的源码和测试。通过 PR/issue/设计文档追溯动机,但以发布 tag 确认交付状态。将 BCL 实现、JIT 代码生成、GC、SDK 默认值和硬件分成独立变量,不把它们全写成"新 .NET 优化了集合"。性能对比用同一源码、功能校验与尽可能对齐的发布配置,并公开无法对齐的差异。
13.5 评估一个并发结构
先写公开协议:顺序、单次操作的原子边界、完成/取消、容量和过载策略。然后在固定源码中标出线性化点、锁/CAS 范围、发布语义、重试和用户回调边界。测试分为可控交错、长时间压力与业务不变式;验证不丢、不重、顺序和完成协议,而不只比较每秒操作数。"线程安全"不自动保证多键事务、公平、无饥饿或元素对象的内部安全。
十四、发布前的资料与引用审查清单
- 每个可能随版本变化的主张,是否写了 TFM、runtime tag/commit、Unity patch 或包版本?
- 是否把语言规范、API 契约、私有实现、设计动机和性能结果分开?
- 公开 API 是否在目标 reference assembly 或最小项目中编译,而不是只看网页搜索结果?
- 源码引用是否使用完整 SHA 的 permalink,并保存仓库、路径、方法和行号?
- 代码是否明确标注为逐字源码、结构化节选、伪代码或业务示例?
- 是否查看同 tag 测试,并用反例检查文章概括没有超出源码和公开契约?
- PR、issue 或 proposal 是否记录了状态和首个发布版本,没有把提议写成已交付事实?
- 书籍是否写了版次和页码,其产品世代是否与当前结论区分?
- 性能数字是否有源码、输入、环境、功能 oracle、样本量、原始报告与失效条件?
- 对比方案是否完成同一工作,包括顺序、异常、分配、构建和清理边界?
- 是否报告分位数、波动和异常样本,而不是只发布平均值或最佳一次?
- Unity 结论是否记录 Editor、包、API profile、后端、裁剪、平台、设备和构建配置?
- Unity 动态路径是否真正启动 IL2CPP Player 执行,而不是只生成了构建产物?
- Profiler、Deep Profile、Development、Safety Checks 和设备热降频等观察者效应是否在结论中公开?
- 实验原始产物是否可定位、可验证哈希、有保留期,且与人工整理的图表分开?
- dump、快照、trace、路径和输入是否完成隐私、凭据与访问权限审查?
- 所有相对链接、锚点和外部链接是否可达,浮动页面内容是否仍支持原主张?
- 失效链接的替代来源是否与原版本和主张等价,还是无意中改写了结论?
- 同一主张在导览、正文、面试篇和附录中是否共用同一版本边界,没有内部矛盾?
- 如果证据不足,文章是否明确降级为"待验证"或"仅限当前实验",而不是用自信语气填补证据空缺?
这份清单的目标不是让每一句话都堆满脚注,而是让影响正确性、兼容性和性能决策的关键主张可追溯。基础定义可集中引用规范和术语表;源码结论、版本时间线、Unity 兼容性与性能数字则应在最接近主张的地方给出可复核证据。当读者能从一个结论追到版本、代码、测试与原始报告,参考资源才不是文末装饰,而是教材级技术文章的可验证基础设施。
上一篇 :附录 B:源码索引速查
返回 :附录概要