根据目录不同,对于 ILDasm、mscorlib 和 System.Runtime 的反编译存在差异

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都包含大多数相同的类型。

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的更小框架。可移植类库项目模板是主要受益者。

哇,这太神奇了!我猜Xamarin也利用了这种语言投影?非常感谢您发布这个详细的答案。是否有官方文档可以让我更深入地了解这些变化? - Razor
2
这个东西我所知道的地方都没有文档记录。像这样的东西通常最终会在博客中被半文档化,但是David Kean和Mircea Trofin都不是认真的博主。我通过研究参考程序集进行了反向工程,花了我一些时间。SO是缺失的手册。 - Hans Passant
那么,一个带有对“.NET可移植子集”的引用的PCL,该子集指向特定的Profile123子集,进而将Profile123中的类型转发到目标设备上的特定库和版本? - Razor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接