6

我一直在玩 ILDasm 并注意到:

  • 反编译C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Runtime.dll (36KB)只返回一个清单文件。反编译C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.dll (114KB)返回清单和程序集中的所有类型。

  • 反编译C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\mscorlib.dll (38KB)只返回一个清单文件,反编译C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll (5171KB)返回一个清单和程序集中的所有类型。

我找不到任何关于为什么以这种方式构建程序集的信息。

两个程序集目录有什么区别,为什么文件系统上有两个副本?为什么两个程序集中的类型都重复?System.Runtime 和 mscorlib 都包含大多数相同的类型。

4

1 回答 1

14

您在 C:\Program Files (x86)\Reference Assemblies 中找到的程序集是参考程序集。它们在 .NET 4.0 及更高版本中相当特殊,它们不包含任何代码,仅包含类型声明。编译器仅使用此类程序集中的元数据来编译您的代码。在运行时,您会得到一个非常不同的程序集,它是从 GAC 中检索的。

请注意,您会在该目录中找到System.Runtime.dll 的许多副本,尤其是 .NETPortable 目录有许多配置文件,每个配置文件都有自己的该参考程序集的副本。使用不同的类型集,适用于该特定配置文件的类型。

您在 C:\Windows\Microsoft.NET\Framework\v4.0.30319 中找到的程序集是 GAC 中的程序集的副本。无论您实际安装的是什么版本的框架。您永远不应该将这些程序集用于任何事情。尽管那里的许多程序集仍然有 [AssemblyVersion("4.0.0.0")],但它们的内容却大不相同,尤其是在 4.0 和 4.5 之间。您可以在文档中看到这一点,ExtensionAttribute 类就是一个很好的例子。在 .NET 4.0 中,它位于 System.Core.dll 中,在 4.5 及更高版本中,它现在位于 mscorlib.dll 中。如果这些副本不再存在会更好,不幸的是 System.CodeDom、sgen.exe 和遗留工具取决于它们的存在。将它们用作参考可能非常麻烦当程序在安装了不同框架版本的另一台机器上运行时。

因此,请查看 GAC 中的程序集以了解运行时实际发生的情况。自 .NET 4.0 以来也有很大的变化,它现在位于另一个目录中。以前在 c:\windows\assembly,现在在 c:\windows\microsoft.net\assembly。最明显的变化是,它不再具有阻止您导航到该目录中文件的 shell 扩展名。您可以直接导航 GAC 文件夹结构。这有点令人费解,因为包含非托管代码(如 mscorlib.dll)的程序集存储在单独的目录中。看一看,你会很容易弄清楚这个方案。

您会发现 C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll 程序集确实相当空。但是,您可能错过了清单中最重要的细节。它包含很多[TypeForwardedTo] 属性。您会在那里找到的一些片段:

[assembly: TypeForwardedTo(typeof(Action))]
[assembly: TypeForwardedTo(typeof(Action<>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,,,,,>))]
[assembly: TypeForwardedTo(typeof(Action<,,,,,,,,,,,,,,,>))]
// etc, many more

也许你可以看到现在发生了什么,System.Runtime.dll 根本不包含任何代码。它是一种将类型从一个程序集转发到另一个程序集的适配器。.NET 的桌面版本将类型转发到 mscorlib.dll、System.dll、System.ComponentModel.Composition 和 System.Core。

上一句中的“桌面版”是解释为什么这样做的关键。有许多.NET Framework 版本,它们在 System.Runtime 中有不同的转发器。这些适配器组件为 Microsoft 购买了额外的间接级别。它可以帮助您编写与平台无关的 .NET 代码,并且无论您在桌面、商店应用程序、使用 Silverlight 的浏览器、XBox 游戏控制台还是手机上执行它,都无需更改即可运行相同的代码。尽管后者有一个相当不同的框架,一个更小的名为 .NETCore 的框架。可移植类库项目模板是主要受益者。

于 2014-03-30T12:33:08.360 回答