.NET(C#) Internals: as a developer, .net framework in my eyes

简介:

引言

这篇文章我很早很早之前就想写了,本来是想把它作为我开博的第一篇的,但由于种种原因直到现在写出来。本文不是用.NET平台和其余平台(诸如Java)做比较,不去评论孰优孰劣。仅仅是作为一个.NET开发者,介绍一下我眼中的.NET。

1、.NET Framework

.NET Framework包括公共语言运行时(Common Language Runtime,CLR)和框架类库(Framework Class Library,FCL)。

  • CLR是.NET Framework 的基础、核心,提供了包括内存管理、线程管理和远程调用等核心服务。
  • FCL是一个基于面向对象的可重用类型集合,用于支持多种应用的快速开发,诸如ASP.NET Web应用、Windows Form应用、Web Service应用、Windows Presentation Foundation(WPF)应用等。

IC104620 图1、.NET Framework(来自:MSDN)

.NET Framework提供一个托管执行环境、简化开发和部署、整合了多种开发语言。CLR是.NET体系的基础,所有的.NET代码都运行在CLR之上,并且与FCL紧密结合,并由此创建基于.NET的Windows Forms、Web Forms和XML Web Services等应用程序。.NET Framework的下层是操作系统,上层是.NET的高级开发语言(C#、F#等)。

1.1、CLR

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

为了提高平台的可靠性,以及为了达到面向事务的电子商务应用所要求的稳定性级别,CLR还要负责其他一些任务,比如监视程序的运行。按照.NET的说法,在CLR监视之下运行的程序属于“托管”(managed)代码,而不在CLR之下、直接在裸机上运行的应用或者组件属于“非托管”(unmanaged)的代码。

CLR将监视形形色色的常见编程错误,许多年来这些错误一直是软件故障的主要根源,其中包括:访问数组元素越界,访问未分配的内存空间,由于数据体积过大而导致的内存溢出,等等。

可以使用 C# 语言编写托管代码,C# 语言提供了下列优点:

  • 完全面向对象的设计。
  • 非常强的类型安全。
  • 很好地融合了 Visual Basic 的简明性和 C++ 的强大功能。
  • 垃圾回收。
  • 类似于 C 和 C++ 的语法和关键字。
  • 使用委托取代函数指针,从而增强了类型安全和安全性。函数指针通过 unsafe C# 关键字和 C# 编译器 (Csc.exe) 的 /unsafe 选项可用于非托管代码和数据。

1.2、FCL

.NET Framework 类库是一个由 Microsoft .NET Framework 中包含的类、接口和值类型组成的库。该库提供对系统功能的访问,是建立 .NET Framework 应用程序、组件和控件的基础。为便于语言之间进行交互操作,.NET Framework 类型是符合 CLS 的,并因此可在任何编程语言中使用,只要这种语言的编译器符合公共语言规范 (CLS)。NET Framework 包括的类型执行下列功能:

  • 表示基础数据类型和异常。
  • 封装数据结构。
  • 执行 I/O。
  • 访问关于加载类型的信息。
  • 调用 .NET Framework 安全检查。
  • 提供数据访问、多客户端 GUI 和服务器控制的客户端 GUI。

.NET Framework 提供一组丰富的接口以及抽象类和具体(非抽象)类。可以按原样使用这些具体的类,或者在多数情况下从这些类派生您自己的类。若要使用接口的功能,既可以创建实现接口的类,也可以从某个实现接口的 .NET Framework 类中派生类。.NET Framework 类库提供下列命名空间

2、.NET的程序运行

.NET上的程序从源码到执行有以下几个步骤(来自Jeffery Richter的《.NET框架程序设计》):

  • 将源码编译为托管模块;
  • 将托管模块组合为程序集;
  • 加载公共语言运行时CLR;
  • 执行程序集代码。

这几个过程我总结为下图:

运行过程

图2、.NET上的程序运行

关于托管模块与程序集的关系,我理解如下:

CLR实际上不和托管模块打交道,它直接打交道的对象是程序集。程序集由一个或多个托管模块及相关的资源文件逻辑组成。其次,程序集是组件复用,以及实施安全策略和版本策略的最小单位。程序集中有一个托管模块中包含清单(manifest)的数据块,而清单仅仅也是一些元数据表的集合,但是这些表描述了组成程序集所有文件中的公有导出类型,以及一些和程序集相关的资源文件或数据文件。如果程序集只有一个托管模块且没有资源文件,该程序集就是托管模块。

由于CLR不直接和托管模块打交道,所以默认情况下,编译器会将产生的托管模块转换为一个程序集。只有这样程序才能够运行。

2.1、托管模块

托管模块有下列部分组成:

  • PE32或PE32+表头:标准PE文件头,类似于Common Object File Format头。如果头使用PE32格式,文件可以运行在32位或64位的Windows当中。如果头使用PE32+格式,文件必须运行在64位 Windows当中。该头还指名了文件的类型:GUI、CUI或DLL,同时还包含了一个用来指明文件何时创建的时间戳。对于只包含IL代码的模块,PE32(+)中的大量信息都会被忽略。对于包含本地CPU代码的模块,头还包括本地CPU代码的信息。
  • CLR表头:包含标识托管模块的一些信息(可以被CLR或一些工具解析)。包括托管模块所需要的CLR版本号、一些标记、托管模块入口点方法(main方法)的MethodDef元数据标记、以及有关托管模块的元数据(metadata)、资源(resources)、强命名(strong name)、标记(flags)、和其他一些意义不大的信息的位置和大小。
  • 元数据:每个托管模块都包含一些元数据表。元数据表主要分两种:一种用来描述代码中定义的类型和成员。一种用来描述代码中引用的类型和成员。
  • IL代码:编译器在编译源代码时产生的代码。在运行时,CLR将IL编译为本地CPU指令。

2.2、程序集

程序集是CLR操作的对象。程序集由一个或多个托管模块及相关的资源文件逻辑组成。在程序集包含的所有文件中,有一个文件用于保存清单,清单是另外一组元数据表的集合,其中主要包含了程序集中的一部分文件的名称,另外清单文件还描述了程序集的版本、语言文化、发布者、公有导出类型、以及组成该程序集的所有文件。CLR总是先加载包含清单元数据表的文件,然后利用该清单来获取程序集中的其它文件。

使用程序集的原因有:

  • 程序集允许我们分离可重用类型的逻辑表示和物理表示。
  • 可以将类型分别实现在不同的文件中,从而允许在互联网环境中进行增量下载。
  • 可以按需向程序集中添加资源或数据文件。
  • 可以使我们创建的程序集包含一些用不同编程语言实现的类型。

总而言之,程序集是一个可重用、可实施版本策略和安全策略的单元。它允许我们将类型和资源划分到不同的文件中,这样程序集的使用者便可以决定将哪些文件打包一起部署。一旦CLR加载了程序集中包含清单的那个文件,它就可以确定程序集中的其他文件中哪些包含了程序正在引用的类型和资源。任何程序集的使用者仅需要知道包含了清单的文件名。要生成一个程序集,我们必须选择一个托管模块作为清单的保存者。

PS:以上仅为个人愚见,定有不当之处,欢迎指正!当中设计的很多概念也没有深入,以及很多概念也没有引出,如元数据没有深入介绍、FCL也没有一个系统的介绍、未介绍到应用程序域等等。当然要完成这些需要大量篇幅,以后会逐步介绍。




本文转自吴秦博客园博客,原文链接:http://www.cnblogs.com/skynet/archive/2010/05/17/1737028.html,如需转载请自行联系原作者

相关文章
|
9天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
1月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
61 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
1月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
58 1
|
1月前
|
并行计算 安全 Java
C# .NET面试系列四:多线程
<h2>多线程 #### 1. 根据线程安全的相关知识,分析以下代码,当调用 test 方法时 i > 10 时是否会引起死锁? 并简要说明理由。 ```c# public void test(int i) { lock(this) { if (i > 10) { i--; test(i); } } } ``` 在给定的代码中,不会发生死锁。死锁通常是由于两个或多个线程互相等待对方释放锁而无法继续执行的情况。在这个代码中,只有一个线程持有锁,且没有其他线程参与,因此不
101 3
|
3月前
|
Linux C# 开发工具
C#开源的一款友好的.NET SDK管理器
C#开源的一款友好的.NET SDK管理器
|
2天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
1月前
|
Windows
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
|
1月前
|
SQL 存储 关系型数据库
C# .NET面试系列十:数据库概念知识
#### 1. 为什么要一定要设置主键? 设置主键是数据库设计中的一个重要概念,有几个主要原因: 1、唯一性 ```c# 主键必须保证表中的每一行都有唯一的标识。这样可以避免数据冗余和不一致性。如果没有主键或者主键不唯一,就可能出现数据混乱或错误。 ``` 2、查询性能 ```c# 数据库系统通常会使用主键来加速数据检索。主键通常会被索引,这样可以更快速地找到特定行的数据,提高查询效率。 ``` 3、关联性 ```c# 主键常常用于建立表与表之间的关系。在关系数据库中,一个表的主键通常与其他表中的外键建立关联,这种关系对于数据的一致性和完整性非常重要。 ``` 4、数据完
130 1
C# .NET面试系列十:数据库概念知识
|
1月前
|
XML 开发框架 .NET
C# .NET面试系列八:ADO.NET、XML、HTTP、AJAX、WebService
## 第二部分:ADO.NET、XML、HTTP、AJAX、WebService #### 1. .NET 和 C# 有什么区别? .NET(通用语言运行时): ```c# 定义:.NET 是一个软件开发框架,提供了一个通用的运行时环境,用于在不同的编程语言中执行代码。 作用:它为多语言支持提供了一个统一的平台,允许不同的语言共享类库和其他资源。.NET 包括 Common Language Runtime (CLR)、基础类库(BCL)和其他工具。 ``` C#(C Sharp): ```c# 定义: C# 是一种由微软设计的面向对象的编程语言,专门为.NET 平台开发而创建。 作
173 2
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
60 0