背景
在 .NET 走向开源后,我们可以方便的查看 .NET 内部的实现方式,学习和寻找问题,甚至参与到 .NET 的开发中。
前段时间,同事需要查看 C# 的 Task 类 (System.Threading.Tasks) 的一些实现和内部的原理,想找 Task 类的源代码来查看,却遇到了一些阻碍……
本文借此机会介绍两种方式来查看 .NET Core 3.1 的源代码:
- 直接查看 .NET Core 源代码
- 通过反编译来查看实现
本文同样适用于 .NET Core 3.1 之前的 .NET Core 版本;.NET 5 及之后的版本查看源代码的方式有所改变,会在下文相关部分简单提及。选择 3.1 版本是因为当前 .NET Core 最新的 LTS 版本为 3.1,绝大多数公司都会选择使用 LTS 的版本进行开发。所以本文并未过时,还能有用一段时间😂
直接查看 .NET Core 源代码
概念回顾
对于经历过 .NET Framework 时期的巨佬们一定接触过 CLR 和 FCL 这两个概念:
- CLR(Common Language Runtime,公共语言运行时)负责内存管理、垃圾收集、JIT 编译等。
- FCL(.NET Framework Class Library,.NET Framework 类库)是进行 .NET Framework 开发的标准类库,提供了最基本的功能。例如
System
命名空间下的基本类和基类、System.Drawing
命名空间下提供的图形处理功能 、System.Linq
命名空间下提供的 LINQ 扩展方法等。
进入 .NET Core 时代,大家一定见过这张图:
可以看到 .NET Core 一列,Base Libraries 一行中出现了 CoreFX Class Library,它的左边便是 FCL。我们可以理解 CoreFX 就是 .NET Core 的 FCL。而 .NET Core 的 CLR 则被称为 CoreCLR。
获取源代码
要想获得 .NET Core 3.1 的源代码,我们主要关注这两个 Github repo:
注意,刚 clone 到本地时可能看不到源代码,因为默认的 archive
分支只有一篇迁移 repo 的公告,需要将分支切换到想看的版本上才能查看到代码。通过 tag
命令筛选要查看的 .NET Core Runtime 版本:
git tag -l 'v3.1.*'
并通过 checkout
命令切换到对应版本的代码上,例如我想查看 3.1.16
版本的 .NET Core Runtime 对应的实现:
git checkout v3.1.16
我们要找的代码大都位于 src
文件夹下。
理解 CoreCLR 和 CoreFX
结合前面回顾过的概念,我们应该可以明白这两个 repo 的作用。但实际上,这里必须得提及 System.Private.CoreLib.dll
的概念,可以帮助我们理解为什么既需要 CoreCLR 又需要 CoreFX 的源代码,它俩的区别是什么:
CoreCLR 的设计理念是,尽可能少的包含类,只把 CLR 内部工作需要的类(例如 System.Object
、System.String
、System.Threading.Thread
、System.Threading.Tasks.Task
和大多数基本接口)包含在 CoreCLR 源代码中,并通过 System.Private.CoreLib.dll
提供给 CoreFX。
CoreFX 中虽然也有 System.Object
的声明,并最终生成 System.Runtime.dll
,但其定义属于一种外观(facade),当我们使用到 System.Object
时,引用会被转发到 System.Private.CoreLib.dll
中。
也就是说,如果我们想要查看一些基本类(例如 System.String
、System.Threading.Tasks.Task
),就需要到 CoreCLR 的源代码中寻找,而其它的一些类和方法的实现(例如 LINQ 里的扩展方法是如何工作的)则需要到 CoreFX 源代码中查看。
如何区分代码位于 CoreCLR 还是 CoreFX
使用 .NET Source Browser
可以参考 .NET Source Browser 工具。它可以在线查看当前最高版本的 .NET 源码(仅限最高版本,目前也就是 6.0 preview)。
在左上角的搜索框里输入要查看的类或方法名,如果你需要的内容出现在 System.Private.CoreLib
中,那就需要到 CoreCLR 中查看,否则到 CoreFX 查看。但由于查询的是最高版本的 .NET 源码,结果仅供参考。
使用 Visual Studio
直接上源代码里搜索应该是更常用的方案,先自行判断一下是不是基础类,如果是则优先上 CoreCLR 中查找。使用 Visual Studio 的 转到 功能可以轻松查找各种类、方法等内容。默认快捷键为 Ctrl + T。
由于源代码里大量使用了partial(部分类),而且不同平台(Windows/Linux)实现可能不同,导致一个类或方法会在多个地方实现,请注意甄别,搜索时用最小单位来搜索,以免大海捞针。
.NET Core 3.1 和 .NET 5 的不同
.NET 5 将 .NET Core 相关的几个 repo 合并成为一个名为 /dotnet/runtime 的 repo(不止 CoreCLR 和 CoreFX 这两个,可以参阅 Consolidating .NET GitHub repos 了解)。
虽然合并了,但也差不多,在 /src/coreclr/src/System.Private.CoreLib
文件夹下可以找到 System.Private.CoreLib
相关的代码;而 /src/libraries
中则是原来 CoreFX 的实现。
访问不了 Github 怎么办
由于众所周知的原因,正常访问 Github 变得困难,如果你尝试了很多办法后仍然无法稳定的访问或下载代码,最简单的方法就是注册一个 gitee 账号,并使用 gitee 的导入 GitHub 仓库功能。
请一定使用“从 URL 导入”,上述 GitHub repo 的 URL(后面加不加 .git
都没问题)就是 gitee 导入时需要填写的 GitHub repo url。导入后会在你的账户下生成对应的 repo。
或者干脆都不用注册 gitee,直接用 gitee 提供的“Gitee 极速下载”服务,在里面搜索 CoreCLR 和 CoreFX。
小试牛刀
至此,我们已经获取到 .NET Core 的源代码,并了解了如何进行查看。下面大家可以试一试看看自己一直想查看的 .NET 内部实现吧。
通过反编译来查看实现
隆重向大家推荐 ILSpy ,这是一款开源免费的 .NET 反编译工具,非常好用,是一款能陪伴你走完职业生涯的软件。
获取 ILSpy
可以直接在 Github 的 Release 页面上下载它的 zip 包,解压后可以直接使用,但没有与 Visual Studio 集成。
这里主要介绍它在 Visual Studio 中的应用,有几种方便的办法将它与 Visual Studio 集成:
- 在 Github 的 Release 页面下载 vsix 包
- 如果访问不了 Github 可以尝试 Visual Studio 扩展(扩展 - 管理扩展)中搜索并安装 ILSpy
- 如果 Visual Studio 扩展下载依然很慢,可以直接通过 Visual Studio Marketplace 下载
安装完成后,鼠标右键点击要查看实现的代码,会显示出“用 ILSpy 打开代码”的菜单:
在弹出的 ILSpy 窗口中查看反编译出来的代码:
需要注意的是,这种办法适合只需要看一看的情况,而且反编译得到的代码和源代码不是完全相同的(但执行的结果肯定是一致的)。
总结
之前同事遇到的问题就是,一开始只 clone 了 CoreFX,而 Task 类实际上是在 CoreCLR 的 System.Private.CoreLib
中定义的~ 在 CoreFX 自然查看不到实现代码了。
通过本文的介绍,相信大家一定能快速的查看 .NET Core 的源代码了:
- 直接获取源代码:适用于想要学习了解 .NET 源码、组织方式、调试或致力于参与到 .NET 建设的情况
- 通过 ILSpy 反编译:适用于临时看看某些代码的实现的情况
希望文章能对大家有帮助。
参考
- Understanding .NET (2nd Edition)
- .NET Core, .NET Framework, Xamarin – The “WHAT and WHEN to use it”
- CoreCLR is now Open Source
- .NET 术语表