《通俗易懂,什么是.NET什么是.NET Framework?什么是.NET Core.pdf》由会员分享,可在线阅读,更多相关《通俗易懂,什么是.NET什么是.NET Framework?什么是.NET Core.pdf(50页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、通俗易懂,什么是通俗易懂,什么是.NET?.NET?什么是什么是.NET.NETFrameworkFramework?什么是?什么是.NET Core?.NET Core?阿里巴巴首席工程师经验分享,物超所值。什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的概念,先从类型系统开始讲起,我将通过跨语言操作这个例子来逐渐引入一系列.NET 的相关概念,这主要包括:CLS、CTS(CLI)、FCL、Windows 下 CLR 的相关核心组成、Windows 下托管程序运行概念、什么是.NET Framework,.NET Core,.NET St
2、andard及一些 VS 编译器相关杂项和相关阅读链接。完整的从上读到下则你可以理解个大概的.NET 体系。文章是我一字一字亲手码出来的,每天下班用休息时间写一点,持续了二十来天。且对于文章上下衔接、概念引入花了很多心思,致力让很多概念在本文中显得通俗。但毕竟.NET 系统很庞大,本文篇幅有限,所以在部分小节中我会给出延伸阅读的链接,在文章结尾我给出了一些小的建议,希望能对需要帮助的人带来帮助,如果想与我交流可以文章留言或者加.NET 技术交流群:166843154目录.NET 和 C#是什么关系跨语言和跨平台是什么什么是跨语言互操作,什么是 CLSoCLS 异常什么是 CTS?什么是类库?o
3、什么是基础类库 BCL?o什么是框架类库 FCL?什么是基元类型?System.Object 的意义计算机是如何运行程序的?o什么是 CPU?o什么是高级编程语言?什么是托管代码,托管语言,托管模块?o非托管的异常什么是 CLR,.NET 虚拟机?什么是 CLR 宿主进程,运行时主机?Windows 系统自带.NET Framework.NET Framework 4.0.30319o.NET Framework4.X 覆盖更新o如何确认本机安装了哪些.NET Framework 和对应 CLR 的版本?什么是程序集用 csc.exe 进行编译.NET 程序执行原理oJIT 编译oAOT 编译
4、程序集的规则o程序集的加载方式o强名称程序集o程序集搜索规则o项目的依赖顺序o为什么 Newtonsoft.Json 版本不一致?o如何在编译时加载两个相同的程序集o如何同时调用两个两个相同命名空间和类型的程序集?o共享程序集 GACo延伸应用程序域o跨边界访问oAppDomain 和 AppPool内存o堆栈和堆的区别o线程堆栈o为什么值类型存储在栈上o托管堆模型o选 class 还是 structoGC 管理器o弱引用、弱事件oGC 堆回收o垃圾回收对性能的影响o性能建议.NET 程序执行图.NET 的安全性o基于角色的安全性o代码访问安全性什么是.NETo什么是.NET Framewor
5、ko如何在 VS 中调试.NET Framework 源代码o什么是.NET Coreo什么是.NET Standardo.NET 官方开源项目链接Visual Studioosln 解决方案o项目模板ocsproj 工程文件o项目属性杂项oIntelliTrace 智能追溯o链接建议语言,是人们进行沟通表达的主要方式。编程语言,是人与机器沟通的表达方式。不同的编程语言,其侧重点不同。有的编程语言是为了科学计算而开发的,所以其语法和功能更偏向于函数式思想。有些则是为了开发应用程序而创立的,所以其语法和功能更为均衡全面。微软公司是全球最大的电脑软件提供商,为了占据开发者市场,进而在 2002 年
6、推出了 VisualStudio(简称 VS,是微软提供给开发者的工具集).NET 1.0 版本的开发者平台。而为了吸引更多的开发者涌入平台,微软还在 2002 年宣布推出一个特性强大并且与.NET 平台无缝集成的编程语言,即 C#1.0 正式版。只要是.NET 支持的编程语言,开发者就可以通过.NET 平台提供的工具服务和框架支持便捷的开发应用程序。C#就是为宣传.NET 而创立的,它直接集成于 Visual Studio.NET 中,VB 也在.NET 1.0 发布后对其进行支持,所以这两门语言与.NET 平台耦合度很高,并且.NET 上的技术大多都是以 C#编程语言为示例,所以经常就.N
7、ET 和 C#混为一谈(实质上它们是相辅相成的两个概念)。而作为一个开发者平台,它不仅仅是包含开发环境、技术框架、社区论坛、服务支持等,它还强调了平台的跨语言、跨平台编程的两个特性。跨语言:即只要是面向.NET 平台的编程语言(C#、Visual Basic、C+/CLI、Eiffel、F#、IronPython、IronRuby、PowerBuilder、Visual COBOL 以及 Windows PowerShell),用其中一种语言编写的类型可以无缝地用在另一种语言编写的应用程序中的互操作性。跨平台:一次编译,不需要任何代码修改,应用程序就可以运行在任意有.NET 框架实现的平台上,
8、即代码不依赖于操作系统,也不依赖硬件环境。每门语言在最初被设计时都有其在功能和语法上的定位,让不同的人使用擅长的语言去干合适的事,这在团队协作时尤为重要。.NET 平台上的跨语言是通过 CLS 这个概念来实现的,接下来我就以 C#和 VB 来演示 什么是.NET 中的跨语言互操作性。通俗来说,虽然 c#和 vb 是两个不同的语言,但此处 c#写的类可以在 vb 中当做自家写的类一样正常使用。比如我在 vb 中写了一个针对 String 的首字母大写的扩展方法,将其编译后的 dll 引用至 C#项目中。在 C#项目中,可以像自身代码一样正常使用来自 vb 这个 dll 的扩展方法。现在有那么多面
9、向对象语言,但不是所有编程语言都能这样直接互操作使用,而.NET 平台支持的 C#和 VB 之所以能这样无缝衔接,先读而后知,后文将会介绍缘由。不过虽然.NET 平台提供了这样一个互操作的特性,但终究语言是不一样的,每个语言有其特色和差异处,在相互操作的时候就会难免遇到一些例外情况。比如我在 C#中定义了一个基类,类里面包含一个公开的指针类型的成员,我想在 vb 中继承这个类,并访问这个公开的成员。但是 vb 语言因为其定位不需要指针,所以并没有 C#中如 int*这样的指针类型,所以在 vb 中访问一个该语言不支持的类型会报错的,会提示:字段的类型不受支持。再比如,C#语言中,对类名是区分大
10、小写的,我在 C#中定义了两个类,一个叫BaseBusiness,另一个叫 baseBusiness。我在 vb 中去继承这个 BaseBusiness 类。如图,在 vb 中访问这个类会报错的,报:BaseBusiness不明确,这是因为在 vb 中对类名是不区分大小写的。在 vb 中,它认为它同时访问了两个一模一样的类,所以按照 vb 的规则这是不合理的。那么为了在 vb 调用 c#的程序集中避免这些因语言的差异性而导致的错误,在编写 c#代码的时候 就应该提前知道 vb 中的这些规则,来应付式的开发。但是,如果我想不仅仅局限于 C#和 VB,我还想我编写的代码在.Net 平台上通用的话,
11、那么我还必须得知道.NET 平台支持的每一种语言和我编写代码所使用的语言的差异,从而在编写代码中避免这些。这几年编程语言层出不穷,在将来.NET 可能还会支持更多的语言,如果说对一个开发者而言掌握所有语言的差异处这是不现实的,所以.NET 专门为此参考每种语言并找出了语言间的共性,然后定义了一组规则,开发者都遵守这个规则来编码,那么代码就能被任意.NET 平台支持的语言所通用。而与其说是规则,不如说它是一组语言互操作的标准规范,它就是公共语言规范-CommonLanguage Specification,简称 CLS CLS 从类型、命名、事件、属性、数组等方面对语言进行了共性的定义及规范。这
12、些东西被提交给欧洲计算机制造联合会 ECMA,称为:共同语言基础设施。就以类型而言,CLS 定义了在 C#语言中符合规范的类型和不符合的有:当然,就编码角度而言,我们不是必须要看那些详略的文档。为了方便开发者开发,.NET 提供了一个特性,名叫:CLSCompliantAttribute,代码被 CLSCompliantAttribute 标记后,如果你写的代码不符合 CLS 规范的话,编译器就会给你一条警告。值得一提的是,CLS 规则只是面向那些公开可被其它程序集访问的成员,如 public、继承的protected,对于该程序集的内部成员如 Private、internal 则不会执行该检
13、测规则。也就是说,所适应的 CLS 遵从性规则,仅是那些公开的成员,而非私有实现。那么有没有那种特殊情况,比如我通过反射技术来访问该程序集中,当前语言并不拥有的类型时会发生什么情况呢?答案是可以尝试的,如用 vb 反射访问 c#中的 char*指针类型,即使 vb 中没有 char*这种等价的指针类型,但 mscorlib 提供了针对指针类型的 Pointer 包装类供其访问,可以从运行时类携带的类型名称看到其原本的类型名。可以看到,该类中的元素是不符合 CLS 规范的。CLSCLS 异常异常提到特殊情况,还要说的一点就是异常处理。.NET 框架组成中定义了异常类型系统,在编译器角度,所有 c
14、atch 捕获的异常都必须继承自 System.Exception,如果你要调用一个 由不遵循此规范的语言 抛出其它类型的异常对象(C+允许抛出任何类型的异常,如 C#调用 C+代码,C+抛出一个 string 类型的异常),在 C#2.0 之前 Catch(Exception)是捕捉不了的,但之后的版本可以。在后续版本中,微软提供了System.Runtime.CompilerServices.RuntimeWrappedException 异常类,将那些不符合 CLS 的包含 Exception 的对象封装起来。并且可以通过 RuntimeCompatibilityAttribute特性来
15、过滤这些异常。RuntimeWrappedException:https:/ CLSCLS 呢?呢?在面向.NET 开发中,编写跨语言组件时所遵循的那些共性,那些规范就叫做 CommonLangrage Specification 简称 CLS,公共语言规范官方 CLS 介绍:https:/ CTSCTS?如果理解了什么是 CLS 的话,那么你将很轻松理解什么是 CTS。假设你已经围绕着封装 继承 多态 这 3 个特性设计出了多款面向对象的语言,你发现大家都是面向对象,都能很好的将现实中的对象模型表达出来。除了语法和功能擅长不同,语言的定义和设计结构其实都差不多一回事。比如,现实中你看到了一辆
16、小汽车,这辆车里坐着两个人,那么如何用这门语言来表达这样的一个概念和场面?首先要为这门语言横向定义一个“类型”的概念。接下来在程序中就可以这样表示:有一个汽车类型,有一个人类型,在一个汽车类型的对象内包含着两个人类型的对象,因为要表达出这个模型,你又引入了“对象”的概念。而现在,你又看到,汽车里面的人做出了开车的这样一个动作,由此你又引入了“动作指令”这样一个概念。接着,你又恍然大悟总结出一个定理,无论是什么样的“类型”,都只会存在这样一个特征,即活着的 带生命特征的(如人)和 死的 没有生命特征的(如汽车)这两者中的一个。最后,随着思想模型的成熟,你发现,这个“类型”就相当于一个富有主体特征
17、的一组指令的集合。好,然后你开始照葫芦画瓢。你参考其它程序语言,你发现大家都是用 class 来表示类的含义,用 struct 表示结构的含义,用 new 来表示 新建一个对象的含义,于是,你对这部分功能的语法也使用 class 和 new 关键字来表示。然后你又发现,他们还用很多关键字来更丰富的表示这些现实模型,比如 override、virtual 等。于是,在不断的思想升级和借鉴后,你对这个设计语言过程中思想的变化仔细分析,对这套语言体系给抽象归纳,最终总结出一套体系。于是你对其它人这样说,我总结出了一门语言很多必要的东西如两种主要类别:值类别和引用类别,五个主要类型:类、接口、委托、结
18、构、枚举,我还规定了,一个类型可以包含字段、属性、方法、事件等成员,我还指定了每种类型的可见性规则和类型成员的访问规则,等等等等,只要按照我这个体系来设计语言,设计出来的语言它能够拥有很多不错的特性,比如跨语言,跨平台等,C#和 VB.net 之所以能够这样就是因为这两门语言的设计符合我这个体系。那么,什么是那么,什么是 CTSCTS 呢?呢?当你需要设计面向.Net 的语言时所需要遵循一个体系(.Net 平台下的语言都支持的一个体系)这个体系就是 CTS(Common Type System 公共类型系统),它包括但不限于:建立用于跨语言执行的框架。提供面向对象的模型,支持在.NET 实现上
19、实现各种语言。定义处理类型时所有语言都必须遵守的一组规则(CLS)。提供包含应用程序开发中使用的基本基元数据类型(如 Boolean、Byte、Char 等)的库。上文的 CLS 是 CTS(Common Type System 公共类型系统)这个体系中的子集。一个编程语言,如果它能够支持 CTS,那么我们就称它为面向.NET 平台的语言。官方 CTS 介绍:https:/ CTS 中有一条就是要求基元数据类型的类库。我们先搞清什么是类库?类库就是类的逻辑集合,你开发工作中你用过或自己编写过很多工具类,比如搞 Web 的经常要用到的JsonHelper、XmlHelper、HttpHelper
20、 等等,这些类通常都会在命名为 Tool、Utility 等这样的项目中。像这些类的集合我们可以在逻辑上称之为 类库,比如这些 Helper 我们统称为工具类库。什么是基础类库什么是基础类库 BCLBCL?当你通过 VS 创建一个项目后,你这个项目就已经引用好了通过.NET 下的语言编写好的一些类库。比如控制台中你直接就可以用 ConSole 类来输出信息,或者 using System.IO 即可通过 File 类对文件进行读取或写入操作,这些类都是微软帮你写好的,不用你自己去编写,它帮你编写了一个面向.NET 的开发语言中使用的基本的功能,这部分类,我们称之为 BCL(BaseClass
21、Library),基础类库,它们大多都包含在 System 命名空间下。基础类库 BCL 包含:基本数据类型,文件操作,集合,自定义属性,格式设置,安全属性,I/O 流,字符串操作,事件日志等的类型什么是框架类库什么是框架类库 FCLFCL?有关 BCL 的就不在此一一类举。.NET 之大,发展至今,由微软帮助开发人员编写的类库越来越多,这让我们开发人员开发更加容易。由微软开发的类库统称为:FCL,Framework ClassLibrary,.NET 框架类库,我上述所表达的 BCL 就是 FCL 中的一个基础部分,FCL 中大部分类都是通过 C#来编写的。在 FCL 中,除了最基础的那部分
22、 BCL 之外,还包含我们常见的 如:用于网站开发技术的ASP.NET 类库,该子类包含 webform/webpage/mvc,用于桌面开发的 WPF 类库、WinForm 类库,用于通信交互的 WCF、 web api、Web Service 类库等等像上文在 CTS 中提到了 基本基元数据类型,大家知道,每门语言都会定义一些基础的类型,比如 C#通过 int 来定义整型,用 string 来定义 字符串,用 object 来定义 根类。当我们来描述这样一个类型的对象时可以有这两种写法,如图:我们可以看到,上边用首字母小写的蓝色体 string、object 能描述,用首字母大写的浅蓝色S
23、tring、Object 也能描述,这两种表述方式有何不同?要知道,在 vs 默认的颜色方案中,蓝色体 代表关键字,浅蓝色体 代表类型。那么这样也就意味着,由微软提供的 FCL 类库里面 包含了 一些用于描述数据类型的 基础类型,无论我们使用的是什么语言,只要引用了 FCL,我们都可以通过 new 一个类的方式来表达数据类型。如图:用 new 来创建这些类型的对象,但这样就太繁琐,所以 C#就用 int 关键字来表示System.Int32,用 string 关键字来表示 System.String 等,所以我们才能这样去写。像这样被表述于编译器直接支持的类型叫做基元类型,它被直接映射于 BC
24、L 中具体的类。下面是部分面向.NET 的语言的基元类型与对应的 BCL 的类别图:说起类型,这里要说 CTS 定义的一个非常重要的规则,就是类与类之间只能单继承,System.Object 类是所有类型的根,任何类都是显式或隐式的继承于 System.Object。System.Object 定义了类型的最基本的行为:用于实例比较的 Equals 系列方法、用于Hash 表中 Hash 码的 GetHashCode、用于 Clr 运行时获取的类型信息 GetType、用于表示当前对象字符串的 ToString、用于执行实例的浅复制 MemberwiseClone、用于 GC 回收前操作的析构
25、方法 Finalize 这 6 类方法。所以 Object 不仅是 C#语言的类型根、还是 VB 等所有面向.NET 的语言的类型根,它是整个FCL 的类型根。当然,CTS 定义了单继承,很多编程语言都满足这个规则,但也有语言是例外,如 C+就不做继承限制,可以继承多个,C+/CLI 作为 C+在对.NET 的 CLI 实现,如果在非托管编码中多继承那也可以,如果试图在托管代码中多继承,那就会报错。我前面已经举过这样特殊情况的例子,这也在另一方面反映出,各语言对 CTS 的支持并不是都如 C#那样全面的,我们只需明记一点:对于符合 CTS 的那部分自然就按照 CTS 定义的规则来。任何可遵循
26、CTS 的类型规范,同时又有.NET 运行时的实现的编程语言就可以成为.NET 中的一员。接下来我要说什么是.NET 的跨平台,并解释为什么能够跨语言。不过要想知道什么是跨平台,首先你得知道一个程序是如何在本机上运行的。什么是什么是 CPUCPUCPU,全称 Central Processing Unit,叫做中央处理器,它是一块超大规模的集成电路,是计算机组成上必不可少的组成硬件,没了它,计算机就是个壳。无论你编程水平怎样,你都应该先知道,CPU 是一台计算机的运算核心和控制核心,CPU 从存储器或高速缓冲存储器中取出指令,放入指令寄存器,并对指令译码,执行指令。我们运行一个程序,CPU 就
27、会不断的读取程序中的指令并执行,直到关闭程序。事实上,从电脑开机开始,CPU 就一直在不断的执行指令直到电脑关机。什么是高级编程语言什么是高级编程语言在计算机角度,每一种 CPU 类型都有自己可以识别的一套指令集,计算机不管你这个程序是用什么语言来编写的,其最终只认其 CPU 能够识别的二进制指令集。在早期计算机刚发展的时代,人们都是直接输入 01010101 这样的没有语义的二进制指令来让计算机工作的,可读性几乎没有,没人愿意直接编写那些没有可读性、繁琐、费时,易出差错的二进制 01 代码,所以后来才出现了编程语言。编程语言的诞生,使得人们编写的代码有了可读性,有了语义,与直接用 01 相比
28、,更有利于记忆。而前面说了,计算机最终只识别二进制的指令,那么,我们用编程语言编写出来的代码就必须要转换成供机器识别的指令。就像这样:code:1+2function 翻译方法(参数:code).1=001;2=002;+=000;return 能让机器识别的二进制代码;call 翻译方法(1+2)=001 000 002所以从一门编程语言所编写的代码文件转换成能让本机识别的指令,这中间是需要一个翻译的过程。而我们现在计算机上是运载着操作系统的,光翻译成机器指令也不行,还得让代码文件转化成可供操作系统执行的程序才行。那么这些步骤,就是编程语言所对应的编译环节的工程了。这个翻译过程是需要工具来完
29、成,我们把它叫做 编译器。不同厂商的 CPU 有着不同的指令集,为了克服面向 CPU 的指令集的难读、难编、难记和易出错的缺点,后来就出现了面向特定 CPU 的特定汇编语言,比如我打上这样的 x86 汇编指令mov ax,bx,然后用上用机器码做的汇编器,它将会被翻译成 1000100111011000 这样的二进制 01 格式的机器指令.不同 CPU 架构上的汇编语言指令不同,而为了统一一套写法,同时又不失汇编的表达能力,C语言就诞生了。用 C 语言写的代码文件,会被 C 编译器先转换成对应平台的汇编指令,再转成机器码,最后将这些过程中产生的中间模块链接成一个可以被操作系统执行的程序。那么汇
30、编语言和 C 语言比较,我们就不需要去阅读特定 CPU 的汇编码,我只需要写通用的 C源码就可以实现程序的编写,我们用将更偏机器实现的汇编语言称为低级语言,与汇编相比,C 语言就称之为高级语言。在看看我们 C#,我们在编码的时候都不需要过于偏向特定平台的实现,翻译过程也基本遵循这个过程。它的编译模型和 C 语言类似,都是属于这种间接转换的中间步骤,故而能够跨平台。所以就类似于 C/C#等这样的高级语言来说是不区分平台的,而在于其背后支持的这个 翻译原理 是否能支持其它平台。什么是托管代码,托管语言,托管模块?什么是托管代码,托管语言,托管模块?作为一门年轻的语言,C#借鉴了许多语言的长处,与
31、C 比较,C#则更为高级。往往一段简小的 C#代码,其功能却相当于 C 的一大段代码,并且用 C#语言你几乎不需要指针的使用,这也就意味着你几乎不需要进行人为的内存管控与安全考虑因素,也不需要多懂一些操作系统的知识,这让编写程序变得更加轻松和快捷。如果说 C#一段代码可以完成其它低级语言一大段任务,那么我们可以说它特性丰富或者类库丰富。而用 C#编程不需要人为内存管控是怎么做到的呢?.NET 提供了一个垃圾回收器(GC)来完成这部分工作,当你创建类型的时候,它会自动给你分配所需要的这部分内存空间。就相当于,有一个专门的软件或进程,它会读取你的代码,然后当你执行这行代码的时候,它帮你做了内存分配
32、工作。这部分本该你做的工作,它帮你做了,这就是“托管”的概念。比如现实中 托管店铺、托管教育等这样的别人替你完成的概念。因此,C#被称之为托管语言。C#编写的代码也就称之为托管代码,C#生成的模块称之为托管模块等。(对于托管的资源,是不需要也无法我们人工去干预的,但我们可以了解它的一些机制原理,在后文我会简单介绍。)只要有比较,就会产生概念。那么在 C#角度,那些脱离了.NET 提供的诸如垃圾回收器这样的环境管制,就是对应的 非托管了。非托管的异常非托管的异常我们编写的程序有的模块是由托管代码编写,有的模块则调用了非托管代码。在.NETFramework 中也有一套基于此操作系统 SEH 的异
33、常机制,理想的机制设定下我们可以直接通过 catch(e)或 catch 来捕获指定的异常和框架设计人员允许我们捕获的异常。而异常类型的级别也有大有小,有小到可以直接框架本身或用代码处理的,有大到需要操作系统的异常机制来处理。.NET 会对那些能让程序崩溃的异常类型给进行标记,对于这部分异常,在.NET Framework 4.0 之前允许开发人员在代码中自己去处理,但 4.0 版本之后有所变更,这些被标记的异常默认不会在托管环境中抛出(即无法 catch 到),而是由操作系统的 SEH 机制去处理。不过如果你仍然想在代码中捕获处理这样的异常也是可以的,你可以对需要捕获的方法上标记System
34、.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute特性,就可以在该方法内通过 catch 捕获到该类型的异常。你也可以通过在配置文件中添加运行时节点来对全局进行这样的一个配置:HandleProcessCorruptedStateExceptions 特性:https:/ 类:https:/ 不仅提供了自动内存管理的支持,他还提供了一些列的如类型安全、应用程序域、异常机制等支持,这些 都被统称为 CLR 公共语言运行库。CLR 是.NET 类型系统的基础,所有的.NET 技术都是建立在此之上,熟悉它
35、可以帮助我们更好的理解框架组件的核心、原理。在我们执行托管代码之前,总会先运行这些运行库代码,通过运行库的代码调用,从而构成了一个用来支持托管程序的运行环境,进而完成诸如不需要开发人员手动管理内存,一套代码即可在各大平台跑的这样的操作。这套环境及体系之完善,以至于就像一个小型的系统一样,所以通常形象的称 CLR 为.NET 虚拟机。那么,如果以进程为最低端,进程的上面就是.NET 虚拟机(CLR),而虚拟机的上面才是我们的托管代码。换句话说,托管程序实际上是寄宿于.NET 虚拟机中。那么相对应的,容纳.NET 虚拟机的进程就是 CLR 宿主进程了,该程序称之为运行时主机。这些运行库的代码,全是
36、由 C/C+编写,具体表现为以 mscoree.dll 为代表的核心 dll 文件,该 dll 提供了 N 多函数用来构建一个 CLR 环境,最后当运行时环境构建完毕(一些函数执行完毕)后,调用_CorDllMain 或_CorExeMain 来查找并执行托管程序的入口方法(如控制台就是Main 方法)。如果你足够熟悉 CLR,那么你完全可以在一个非托管程序中通过调用运行库函数来定制 CLR并执行托管代码。像 SqlServer 就集成了 CLR,可以使用任何.NET Framework 语言编写存储过程、触发器、用户定义类型、用户定义函数(标量函数和表值函数)以及用户定义的聚合函数。有关 C
37、LR 大纲介绍:https:/ 集成:https:/ CLR 的接口:https:/ Framework 2.0 的宿主接口:https:/ CLR 版本:https:/ C#编写的程序如果想运行就必须要依靠.NET 提供的 CLR 环境来支持。而 CLR 是.NET技术框架中的一部分,故只要在 Windows 系统中安装.NET Framework 即可。Windows 系统默认安装的有.NET Framework,并且可以安装多个.NET Framework 版本,你也不需要因此卸载,因为你使用的应用程序可能依赖于特定版本,如果你移除该版本,则应用程序可能会中断。Microsoft.NET
38、 Framework 百度百科下有 windows 系统默认安装的.NET 版本图出自 https:/ 下的 Framework 和 Framework64 文件夹中分别可以看到 32 位和 64 位的.NET Framework 安装的版本。我们点进去可以看到以.NET 版本号为命名的文件夹,有 2.0,3.0,3.5,4.0 这几个文件夹。.NET Framework4.X.NET Framework4.X 覆盖更新覆盖更新要知道.NET Framework 版本目前已经迭代到 4.7 系列,电脑上明明安装了比 4.0 更高版本的.NET Framework,然而从文件夹上来看,最高不过
39、4.0,这是为何?原来自.NET Framework 4 以来的所有.NET Framework 版本都是直接在 v4.0.30319文件夹上覆盖更新,并且无法安装以前的 4.x 系列的老版本,所以 v4.0.30319 这个目录中其实放的是你最后一次更新的 NET Framework 版本。.NET Framework 覆盖更新:https:/ Framework.NET Framework 和对应和对应 CLRCLR 的版本?的版本?我们可以通过注册表等其它方式来查看安装的最新版本:https:/ Framework 版本,比如 csc.exe 文件。上文我介绍了编译器,即将源代码文件给翻
40、译成一个计算机可识别的二进制程序。而在.NETFramework 目录文件夹中就附带的有 用于 C#语言的命令行形式的编译器 csc.exe 和 用于VB 语言的命令行形式的编译器 vbc.exe。我们通过编译器可以将后缀为.cs(C#)和.vb(VB)类型的文件编译成程序集。程序集是一个抽象的概念,不同的编译选项会产生不同形式的程序集。以文件个数来区分的话,那么就分 单文件程序集(即一个文件)和多文件程序集(多个文件)。而不论是单文件程序集还是多文件程序集,其总有一个核心文件,就是表现为后缀为.dll或.exe 格式的文件。它们都是标准的 PE 格式的文件,主要由 4 部分构成:1.PE 头
41、,即 Windows 系统上的可移植可执行文件的标准格式2.CLR 头,它是托管模块特有的,它主要包括o1)程序入口方法o2)CLR 版本号等一些标志o3)一个可选的强名称数字签名o4)元数据表,主要用来记录了在源代码中定义和引用的所有的类型成员(如方法、字段、属性、参数、事件.)的位置和其标志 Flag(各种修饰符)正是因为元数据表的存在,VS 才能智能提示,反射才能获取 MemberInfo,CLR 扫描元数据表即可获得该程序集的相关重要信息,所以元数据表使得程序集拥有了自我描述的这一特性。clr2 中,元数据表大概 40 多个,其核心按照用途分为 3类:o1.即用于记录在源代码中所定义的
42、类型的定义表:ModuleDef、TypeDef、MethodDef、ParamDef、FieldDef、PropertyDef、EventDef,o2.引用了其它程序集中的类型成员的引用表:MemberRef、AssemblyRef、ModuleRef、TypeRefo3.用于描述一些杂项(如版本、发布者、语言文化、多文件程序集中的一些资源文件等)的清单表:AssemblyDef、FileDef、ManifestResourceDef、ExportedTypeDef3.IL 代码(也称 MSIL,后来被改名为 CIL:Common Intermediate Language 通用中间语言),
43、是介于源代码和本机机器指令中间的代码,将通过 CLR 在不同的平台产生不同的二进制机器码。4.一些资源文件多文件程序集的诞生场景有:比如我想为.exe 绑定资源文件(如 Icon 图标),或者我想按照功能以增量的方式来按需编译成.dll 文件。通常很少情况下才会将源代码编译成多文件程序集,并且在 VS IDE 中总是将源代码给编译成单文件的程序集(要么是.dll 或.exe),所以接下来我就以单文件程序集为例来讲解。现在,我将演示一段文本是如何被 csc.exe 编译成一个可执行的控制台程序的。我们新建个记事本,然后将下面代码复制上去。View Code然后关闭记事本,将之.txt 的后缀改为
44、.cs 的后缀(后缀是用来标示这个文件是什么类型的文件,并不影响文件的内容)。上述代码相当于 Web 中的 http.sys 伪实现,是建立了通信的 socket 服务端,并通过 while循环来不断的监视获取包的数据实现最基本的监听功能,最终我们将通过 csc.exe 将该文本文件编译成一个控制台程序。我已经在前面讲过 BCL,基础类库。在这部分代码中,为了完成我想要的功能,我用到了微软已经帮我们实现好了的 String 数据类型系列类(.NET 下的一些数据类型)、Environment 类(提供有关当前环境和平台的信息以及操作它们的方法)、Console 类(用于控制台输入输出等)、So
45、cket 系列类(对 tcp 协议抽象的接口)、File 文件系列类(对文件目录等操作系统资源的一些操作)、Encoding 类(字符流的编码)等这些类,都属于 BCL 中的一部分,它们存在但不限于 mscorlib.dll、System.dll、System.core.dll、System.Data.dll 等这些程序集中。附:不要纠结 BCL 到底存在于哪些 dll 中,总之,它是个物理分散,逻辑上的类库总称。mscorlib.dll 和 System.dll 的区别:https:/ using 这些类的命名空间,并通过csc.exe 中的/r:dll 路径 命令来为生成的程序集注册元数据
46、表(即以 AssemblyRef 为代表的程序集引用表)。而这些代码引用了 4 个命名空间,但实际上它们只被包含在 mscorlib.dll 和 System.dll 中,那么我只需要在编译的时候注册这两个 dll 的信息就行了。好,接下来我将通过 cmd 运行 csc.exe 编译器,再输入编译命令:csc/out:D:demo.exeD:dicdemo.cs/r:D:dicSystem.dll/r:是将引用 dll 中的类型数据注册到程序集中的元数据表中。/out:是输出文件的意思,如果没有该命令则默认输出name.exe。使用 csc.exe 编译生成:https:/ 编译命令行介绍:h
47、ttps:/ 后缀的 c#格式文件,2.是 代码语法等检测分析必须正确,3.是 使用的类库必须有出处(引用的 dll),当然 因为我是编译为控制台程序,所以还必须得有个静态 Main 方法入口,以上缺一不可。可以看出,这段命令我是将 位于 D:dic的 demo.cs 文件给编译成 位于 D:名为 demo.exe的控制台文件,并且因为在代码中使用到了 System.dll,所以还需要通过/r 注册该元数据表。这里得注意为什么没有/r:mscorlib.dll,因为 mscorlib.dll 地位的特殊,所以 csc 总是对每个程序集进行 mscorlib.dll 的注册(自包含引用该 dll
48、),因此我们可以不用/r:mscorlib.dll 这个引用命令,但为了演示效果我还是决定通过/nostdlib 命令来禁止 csc 默认导入 mscorlib.dll 文件。所以,最终命令是这样的:csc D:dicdemo.cs/r:D:dicmscorlib.dll/r:D:dicSystem.dll/nostdlib因为没有指定输出文件/out 选项,所以会默认输出在与 csc 同一目录下名为 demo.exe 的文件。事实上,在 csc 的命令中,如果你没有指定路径,那么就默认采用在 csc.exe 的所在目录的相对路径。而我们可以看到,在该目录下有许多程序集,其中就包含我们需要的
49、System.dll 和mscorlib.dll,所以我们完全可以直接/r:mscorlib.dll/r:System.dll而类似于 System.dll、System.Data.dll 这样使用非常频繁的程序集,我们其实不用每次编译的时候都去手动/r 一下,对于需要重复劳动的编译指令,我们可以将其放在后缀为.rsp 的指令文件中,然后在编译时直接调用文件即可执行里面的命令 name.rsp。csc.exe 默认包含 csc.rsp 文件,我们可以用/noconfig 来禁止默认包含,而 csc.rsp 里面已经写好了我们会经常用到的指令。所以,最终我可以这样写 csc D:dicdemo.
50、cs 直接生成控制台应用程序。.NET.NET 程序执行原理程序执行原理好的,现在我们已经有了一个 demo.exe 的可执行程序,它是如何被我们运行的?。C#源码被编译成程序集,程序集内主要是由一些元数据表和 IL 代码构成,我们双击执行该exe,Windows 加载器将该 exe(PE 格式文件)给映射到虚拟内存中,程序集的相关信息都会被加载至内存中,并查看 PE 文件的入口点(EntryPoint)并跳转至指定的 mscoree.dll 中的_CorExeMain 函数,该函数会执行一系列相关 dll 来构造 CLR 环境,当 CLR 预热后调用该程序集的入口方法 Main(),接下来由