返回「计算机、信息技术与工程」

【.NET】 .NET Framework & Mono & IL语言知识点整理

更多
Markdown 结构化数据
本文目录 29 个章节

【.NET】 .NET Framework & Mono & IL语言知识点整理

创建时间:2020/4/28 10:46

  • 【.NET】 .NET Framework & Mono & IL语言 知识点整理
    • .Net Framework
      • CLI
      • JIT(即时编译)
      • JIT编译与解释器
      • C Sharp
      • CIL or IL
        • IL语言和汇编语言的区别
      • CLR
      • 托管代码和非托管代码
        • 托管代码
        • 非托管代码
    • Assembly
      • 笔者的理解
      • Managed Module
        • Windows PE文件头
        • CLR文件头
        • 元数据
      • Assembly和Managed Module的关系
    • C#的编译执行过程
      • 手动编译c#脚本并运行的过程
      • VM的好处
    • Unity Mono
      • Boo, JavaScript(Unity Script), C
    • 工具整理
      • ildasm, ilasm, csc
      • Mono.Cecil
      • dnSpy
    • .NET vs JAVA
    • Reference

.Net Framework

一个致力于敏捷软件开发(agile software development)、快速应用开发(rapid application development)、平台无关性和网络透明化的软件框架。 是以一种采用系统虚拟机运行的编程平台,以通用语言运行库(Common Language Runtime)为基础,支持多种语言(C#、F#、VB.NET、C++、Python等)的开发。

CLI

通用语言基础架构(Common Language Infrastructure,简称CLI)是一个开放的 技术规范 。包括一般系统、基础类库和与机器无关的中间代码。

CLI定义了构成.NET Framework基础结构的可执行码以及代码的运行时环境的规范,它定义了一个语言无关的跨体系结构的运行环境,这使得开发者可以用规范内定义的各种高级语言来开发软件,并且无需修正即可将软件运行在不同的计算机体系结构上。

通用语言运行库(CLR)则是微软对此标准(CLI)的实现。 如果一种语言实现生成了CLI,它也可以通过使用CLR被调用,这样它就可以与任何其他.NET语言生成的数据相交互。

JIT(即时编译)

别名: 及时编译,实时编译,动态翻译,运行时编译 即时编译(just-in-time compilation, JIT)是一种 执行计算机代码的方法 。在程序执行过程中(在运行期)而不是在执行之前进行编译。括源代码或更常见的字节码到机器码的 转换 ,然后直接 执行 。转换是在程序执行的过程中逐渐进行的。 实现JIT编译器的系统通常会不断地分析正在执行的代码,并确定代码的某些部分,在这些部分中,编译或重新编译所获得的加速将超过编译该代码的开销。 即时编译技术提供了特定环境下的最佳化、运行时类型安全以及汇编验证。为此,即时编译器检查程序集元数据中是否有非法访问和句柄的冲突。

JIT编译与解释器

JIT编译的一个常见实现是首先进行AOT编译,把 源代码 编译成 字节码 (虚拟机代码),称为 字节码编译 ,然后将JIT编译为 机器码动态编译 ),而不是解释字节码。与解释相比,这提高了运行时性能,但代价是编译造成的延迟。与解释器一样,JIT编译器不断地进行翻译,但是对编译后的代码进行缓存可以最大限度地减少在给定运行期间将来执行相同代码的延迟。 使用JIT技术的一个共同目标是达到或超过静态编译的性能,同时保持字节码解释的优势

C Sharp

C#是微软推出的一种基于.NET框架的、面向对象的高级编程语言。C#是一种由C和C++派生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性,使其成为C语言家族中的一种高效强大的编程语言。C#以.NET框架类库作为基础,拥有类似Visual Basic的快速开发能力。

CIL or IL

是一种属于通用语言架构和.NET框架的低阶(lowest-level)的人类可读的编程语言。 目标为.NET框架的 语言 被编译成 CIL ,然后汇编成 字节码

CIL特指在.Net平台下的IL标准

CIL (Common Intermediate Language,通用中间语言)或 IL (Intermediate Language ,中间语言):是一种解释语言(interpretative language), 是.NET唯一懂得的语言,上层代码编译完成后都要转换为中间语言供CLR使用。中间语言使得在.Net中各种语言的方便交互成为了可能。

可以将 IL 视为一个面向对象的机器语言,并且它是完全基于堆栈的,运行在虚拟机上(.Net Framework, Mono VM)

  • IL代码 :二进制格式的字节码。是将 C# 通过 csc 编译器编译成的中间语言代码。也称为托管代码,因为它是由 CLR 生成的,也会由 CLR 进行管理。

中间语言代码在运行时还会被 JIT 再次转换为高级码(面向特定 CPU 架构,例如 x86、x64 等)。

  • IL语言 :文本格式的IL编程语言。

框架类库(Framework Class Library,简称FCL)程序集 :.net框架中包括有一组.net 框架类库程序集 ,其中含 有几千个类型的定义,每个类型都提供了某种功能。

CSC编译过程会将C#代码先转换为IL语言程序再调用ilasm将其编译为IL代码吗?还是C#代码直接编译为IL代码? 做个小试验,将ilasm.exe改个名字让系统找不到。结果:csc一样能编译成功,看来CSC是直接生成IL代码的。

IL语言和汇编语言的区别

IL和汇编的区别是显著的。IL拥有各种高级特性,它知道什么是范型,什么是类和方法(以及它们的“名称”),什么是继承,什么是字符串,布尔值,什 么是User对象。而CPU只知道寄存器,地址,内存,01010101。与汇编相比,IL简直太高级了,几乎完全是一个高级语言,比C语言还要高级。因 此,您会看到.NET Reflector几乎可以把IL代码“一五一十”地反编译为可读性良好的C#代码,包括类,属性,方法等等;而从汇编只能勉勉强强地反编译为C语言 —— 而且其中的“方法名”等信息已经完全不可恢复了,更别说“模块”等高级抽象的内容。您想要把汇编反编译成C#代码?相信在将来这是可行的,不过现在 这还是天方夜谭。

CLR

公共语言运行时 (common language runtime,CLR) 是托管代码执行核心中的引擎。为托管代码提供各种服务,如跨语言集成、代码访问安全性、对象生存期管理、调试和分析支持。它是整个.NET框架的核心,它为.NET应用程序提供了一个托管的代码执行环境。它实际上是驻留在内存里的一段代理代码,负责应用程序在整个执行期间的代码管理工作。

包含以下规范: 通用类型系统(Common Type System, CTS) 元数据系统(Metadata) 通用语言规范(Common Language Specification, CLS) 虚拟执行系统(Virtual Execution System, VES) 通用中间语言(Common Intermediate Language, CIL) 框架(Framework)

和Java虚拟机一样也是一个运行时环境,它负责 资源管理 (内存分配和垃圾收集),并保证 应用和底层操作系统 之间必要的 分离

特性:操作系统无关性

windows自带一个CLR,用来解释运行C#程序集

托管代码和非托管代码

托管代码

托管代码是在公共语言运行库中运行的代码,托管代码的执行由公共语言运行库来直接控制,而不是操作系统来直接控制。具体而言,由公共语言运行库中的代码管理器来控制和执行托管代码,而公共语言运行库的其他部分会提供托管代码执行时所需要的各种服务,如垃圾回收、类型检查、安全支持等。

非托管代码

非托管代码是在托管代码的概念出现后相对于托管代码而言的,其实际上是计算机操纵系统可识别的机器码。非托管代码(机器码)的执行由操作系统来控制,其在执行时也需要各种服务,如垃圾回收、类型检查、安全支持等。由于没有像公共语言运行库这样的东西会自动给你提供服务,所以你需要自己提供这些服务,也就说你要写额外的代码来实现垃圾回收等功能。

Assembly

  • 程序集(Assembly) 是一个可以寄宿于 CLR 中的、拥有版本号的、自解释、可配置的二进制文件(例如 可执行文件.exe类库文件.dll

  • 程序集是一个或多个托管模块的集合,并且作为版本控制、代码重用以及部署的最小单元。 写完代码之后进行生成(build)时,CLR 将 .NET 应用程序打包为由模块(module)组成的程序集(assembly)。

  • 程序集 是代码进行编译时的一个逻辑单元,把相关的代码和类型进行组合,然后生成PE文件。程序集在编译后并不一定会生成单个文件,而可能会生成多个物理文件,甚至可能会生成分布在不同位置的多个物理文件,所以程序集是一个逻辑单元,而不是一个物理单元。对于 静态程序集 可以生成单个或多个文件,而 动态程序集 是存在于内存中的。

任何基于.NET的代码在编译时都至少存在一个程序集(所有.NET项目都会默认引用mscorlib程序集)。

一个程序集可以包含一个或多个 命名空间 ,而每个命名空间中又可以包含子命名空间或类型列表。 由于程序集在编译后可以生成多个模块文件,因此一个物理文件并不代表它就是一个程序集,一个程序集并不一定只有一个文件。

在VS开发环境中,一个解决方案可以包含多个项目,而每个项目就是一个程序集。

Assembly的一个特性 Assembly是.Net环境下类型标识的一部分, 区分一个类型的标识就是包含这个类型的Assembly名字加上类型名本身。

应用程序的结构层次 应用程序域—程序集(Assembly)—模块—类型—成员

笔者的理解

C#语言编译后会生成程序集 一个DLL或EXE文件就对应了一个程序集Assembly Assembly当中包括了类型Type 类型中包括了变量和方法Method 方法的方法体MethodBody中是一条一条的指令Instruction 指令包括操作码OpCode等等

一个小问题: 明明cs源文件比编译后的程序集更容易理解,为何Mono.Cecil要对程序集进行分析,而不直接分析cs源文件? cs源文件更好读,是对于人类来说的。 越高级的语言,人类越容易理解 而越低级、越底层的语言,计算机更容易读,更容易理解。 我们的目的是要让我们的程序,让计算机自动读代码,进行分析,因此,对程序集的分析会更容易。

Managed Module

参考:http://c.biancheng.net/view/3060.html 接下来介绍Managed Module(托管模块)的结构

Windows PE文件头

拥有 Windows PE 文件头的文件可以被 Windows 操作系统加载和操作。

CLR文件头

程序集中的 CLR 文件头使得文件可以寄宿于 CLR。 CLR 文件头告诉操作系统这个文件是一个 .NET 程序集,区别于其他类型的可执行程序。

元数据

元数据记录了模块中的类型及其成员。 它的用途非常广泛,例如,它是反射的基石、IDE 的智能感知、序列化和反序列化也靠它来实现。 通过反射可以访问元数据, 而通过特性,你可以自定义自己想要的元数据。

Assembly和Managed Module的关系

程序集 本质上是 一组托管模块 ,它当然也具有托管模块的所有成分,例如文件头、IL 和元数据。 程序集还包括一个清单( manifest ),令 CLR 知道该程序集所有托管模块的信息,以及它所需要的外部程序集的信息。它还描述了程序集本身的信息,例如程序集标识等(名称、版本、文化),这些都是托管模块所不具备的。 这个清单也位于程序集的某个模块之中,而这个模块就称为 主模块

扩展名为 .dll 或 .exe 的文件称为主模块,扩展名为 netmodule 的文件称为普通模块

在程序运行时,主模块先加载,然后,根据清单就可以找到其他模块以及其他外部程序集的位置(这个过程称为 探测 )。

如何理解托管模块不包含manifest,而manifest又在某主模块中? 董事长拥有有公司的章,而这个章存放在某个员工的手里,我们不能说员工拥有章。一个董事长一定有一个章,而员工不一定有。

除了清单之外,程序集还包括若干 资源文件 ,例如图片文件等。

多个程序集便组成了一个应用程序,一个应用程序也可以只有一个程序集。

程序集是可配置的:可以将其配置为私有或共享(全局程序集缓存,GAC)。

Visual Studio 只能生成 单模块程序集 ,因此,无论是使用 Debug 还是 Release 模式,都不会得到 .module 文件。

C#的编译执行过程

C#或者VB这样遵循CLI规范的 高级语言 ,被先被各自的 编译器 编译成 中间语言 IL(CIL),等到需要真正执行的时候,这些IL会被加载到运行时库 CLR ,也就是VM中,由 VM 动态的编译( JIT )成汇编代码然后在执行。

Alt text

手动编译c#脚本并运行的过程

class MyClass<T, U>
    where T : class
    where U : struct
{ }
  1. vS2017 的开发人员命令提示符(不能是普通的命令提示符)定位到工程文件夹

  2. 编译托管模块

class MyClass<T, U>
    where T : class
    where U : struct
{ }
  1. 合并为程序集
class MyClass<T, U>
    where T : class
    where U : struct
{ }
  1. 编译可执行文件
string str1 = "test";
string str2 = "test";

关于VS编译 : Visual Studio 默认生成的 .dll 中,已经将各个普通模块包含进主模块中,所以除了 .dll 并没有其他的模块文件。 过程

  • 将所有 C# 源代码编译为托管模块(编译结果保存在 obj 目录中)。

  • 将所有托管模块合并为程序集(Visual Studio 只能生成单模块程序集),输出 .dll 或 .exe 文件(结果保存在 bin 目录中),然后,obj 目录中的托管模块就被删除。

VM的好处

VM使得很多动态代码特性得以实现,通过VM我们甚至可以由代码在运行时生成新代码并执行。这个是静态编译语言所无法做到的。 Boo和Unity Script并没有对应的VM虚拟机,Unity中VM只有一个: Mono VM Boo和Unity Script是被各自的编译器编译成遵循CLI规范的IL,然后再由Mono VM解释执行的。这也是Unity Script和JavaScript的根本区别。

Unity Mono

Mono是一个由Xamarin公司所主持的开源项目。Mono包括 C#编译器通用语言架构 。 与微软的.NET Framework(共通语言运行平台)不同,Mono提供了C#编译和运行的平台,可以跨平台运行。

Windows系统,Linux,FreeBSD,Unix,OS X和Solaris,甚至一些游戏平台,如:Playstation 3,Wii 或 XBox 360

相对于微软的.Net Framework运行时库Mono使用自己的Mono VM作为运行时库。

Unity3D最大的一个特点是一次制作,多平台部署,而 这一核心功能是靠Mono实现的。可以说Mono是Unity3D核心的核心,是Unity3D跨平台的根本。

Boo, JavaScript(Unity Script), C

JavaScript: Unity中的JavaScript严格意 义上说并不是W3C规范中的JavaScript,它正确的名字叫做Unity Script,其实是从Boo演变过来的

工具整理

ildasm, ilasm, csc

查看IL文件 C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64 csc.exe : 将 C#代码 编译为dll或者exe形式的 程序集 ,程序集中代码为 IL代码ilasm.exe :是将 IL语言 程序编译为dll或者exe的 程序集 ,程序集中代码也是 IL代码ildasm.exe :将含IL代码的 程序集 dll或者exe反汇编为 IL语言程序

Mono.Cecil

Mono.Cecil对c#程序集当中相应的概念定义了相应的类型。部分如下: AsseblyDefinition Module TypeDefinition MethodDefinition Instruction MethodDebugInformation

dnSpy

反编译和debug工具,可以对DLL文件(程序集)进行反编译,得到c#代码 查看程序集的IL代码 源码:https://github.com/0xd4d/dnSpy

ILSpy是dnSpy的初级版 ILSpy 是一个免费的、开源的反编译工具,可以将程序集反编译为 C# 代码

.NET vs JAVA

公共语言基础(CLI),通用中间语言(CIL)以及C#与甲骨文公司的Java虚拟机和Java之间有不少的相似之处,因此它们无疑是强烈的竞争者。它们两者都使用它们各自的中间码(在微软,它们叫做通用中间语言,而在Oracle,它们叫字节码)。通用中间语言被设计来即时编译(JIT),而Java的字节码在最初的时候则是设计成用于解释运行,而非即时编译。.NET现在只在Windows上被完美地支持,而Java则可在很多平台上被完好支持。然而,现在一些正在开发中的实现版本例如Mono或者Shared source CLI可以用于在类Unix操作系统例如Linux,FreeBSD和Mac OS X上运行.NET应用程序。甲骨文公司的一个产品,J2EE提供与微软的一些捆绑于Windows中的技术例如COM+(先前的MTS)和MSMQ等效的功能。

Java和.NET可经由IKVM,一个在.NET平台上实现的Java虚拟机作更多的沟通。

Java有其专门的远程程序调用技术RMI(Remote Method Invocation), RMI的另一版本RMI-IIOP更可兼容CORBA。

然而,.NET与Java之间的竞争关系,在.NET Core出现后,一切都改观了。

Reference

https://www.cnblogs.com/czx1/p/201413137070-com.html https://blog.csdn.net/iteye_16259/article/details/82544477 http://ask.zol.com.cn/x/12210756.html https://zh.wikipedia.org/wiki/.NET%E6%A1%86%E6%9E%B6 https://zh.wikipedia.org/wiki/%E5%8D%B3%E6%99%82%E7%B7%A8%E8%AD%AF https://zhuanlan.zhihu.com/p/19972689 C#/.NET程序集详解:http://c.biancheng.net/view/3060.html C#程序集与反射技术:https://www.cnblogs.com/czx1/p/201413137070-com.html Unity将来时:IL2CPP是什么?: https://zhuanlan.zhihu.com/p/19972689

C#/.NET程序集详解:http://c.biancheng.net/view/3060.html

其他相关资料 浅谈.NET中的IL代码 https://cloud.tencent.com/developer/article/1335491 读懂IL代码就这么简单 (一) https://www.cnblogs.com/zery/p/3366175.html#!comments 读懂IL代码就这么简单(二) https://www.cnblogs.com/zery/p/3376973.html 30分钟?不需要,轻松读懂IL https://www.cnblogs.com/brookshi/p/5225801.html 【.Net底层剖析】2.stfld指令-给对象的字段赋值 https://cloud.tencent.com/developer/article/1129484 【.Net底层剖析】3.用IL来理解属性 https://cloud.tencent.com/developer/article/1129680 【深入浅出.Net IL】1.一个For循环引发的IL https://cloud.tencent.com/developer/article/1129482 VS2013外部工具中添加ildasm.exe https://cloud.tencent.com/developer/article/1129759 c#程序集系列博客: https://www.cnblogs.com/darrenji/p/3967508.html IL汇编语言介绍: https://www.cnblogs.com/xiaoxiangfeizi/archive/2011/08/08/2130768.html 英文原文: https://www.codeproject.com/Articles/3778/Introduction-to-IL-Assembly-Language IL(中间语言) https://blog.csdn.net/u014605728/article/details/50833458 IL指令表 https://www.cnblogs.com/knowledgesea/p/5461040.html