.NET、NET Framewor以及.NET Core的关系(一)

什么是.NET?什么是.NET Framework?本文将从上往下,按部就班的介绍一系列相关.NET的概念,先从类型系统开始讲起,我将经过跨语言操做这个例子来逐渐引入一系列.NET的相关概念,这主要包括:CLS、CTS(CLI)、FCL、Windows下CLR的相关核心组成、Windows下托管程序运行概念、什么是.NET Framework,.NET Core,.NET Standard及一些VS编译器相关杂项和相关阅读连接。完整的从上读到下则你能够理解个大概的.NET体系。web

文章是我一字一字亲手码出来的,天天下班用休息时间写一点,持续了二十来天。且对于文章上下衔接、概念引入花了不少心思,致力让不少概念在本文中显得通俗。但毕竟.NET系统很庞大,本文篇幅有限,因此在部分小节中我会给出延伸阅读的连接,在文章结尾我给出了一些小的建议,但愿能对须要帮助的人带来帮助,若是想与我交流能够文章留言或者加.NET技术交流群:166843154编程

.NET和C#是什么关系

语言,是人们进行沟通表达的主要方式。编程语言,是人与机器沟通的表达方式。不一样的编程语言,其侧重点不一样。有的编程语言是为了科学计算而开发的,因此其语法和功能更偏向于函数式思想。有些则是为了开发应用程序而创立的,因此其语法和功能更为均衡全面。c#

微软公司是全球最大的电脑软件提供商,为了占据开发者市场,进而在2002年推出了Visual Studio(简称VS,是微软提供给开发者的工具集) .NET 1.0版本的开发者平台。而为了吸引更多的开发者涌入平台,微软还在2002年宣布推出一个特性强大而且与.NET平台无缝集成的编程语言,即C# 1.0正式版。
只要是.NET支持的编程语言,开发者就能够经过.NET平台提供的工具服务和框架支持便捷的开发应用程序。api

C#就是为宣传.NET而创立的,它直接集成于Visual Studio .NET中,VB也在.NET 1.0发布后对其进行支持, 因此这两门语言与.NET平台耦合度很高,而且.NET上的技术大多都是以C#编程语言为示例,因此常常就.NET和C#混为一谈(实质上它们是相辅相成的两个概念)。
而做为一个开发者平台,它不只仅是包含开发环境、技术框架、社区论坛、服务支持等,它还强调了平台的跨语言、跨平台编程的两个特性。数组

跨语言和跨平台是什么

跨语言:即只要是面向.NET平台的编程语言((C#、Visual Basic、C++/CLI、Eiffel、F#、IronPython、IronRuby、PowerBuilder、Visual COBOL 以及 Windows PowerShell)),用其中一种语言编写的类型能够无缝地用在另外一种语言编写的应用程序中的互操做性。
跨平台:一次编译,不须要任何代码修改,应用程序就能够运行在任意有.NET框架实现的平台上,即代码不依赖于操做系统,也不依赖硬件环境。安全

什么是跨语言互操做,什么是CLS

每门语言在最初被设计时都有其在功能和语法上的定位,让不一样的人使用擅长的语言去干合适的事,这在团队协做时尤其重要。
.NET平台上的跨语言是经过CLS这个概念来实现的,接下来我就以C#和VB来演示 什么是.NET中的跨语言互操做性。架构

通俗来讲,虽然c#和vb是两个不一样的语言,但此处c#写的类能够在vb中当作自家写的类同样正常使用。mvc

好比我在vb中写了一个针对String的首字母大写的扩展方法,将其编译后的dll引用至C#项目中。
app

 

在C#项目中,能够像自身代码同样正常使用来自vb这个dll的扩展方法。框架

 

如今有那么多面向对象语言,但不是全部编程语言都能这样直接互操做使用,而.NET平台支持的C#和VB之因此能这样无缝衔接,先读然后知,后文将会介绍原因。不过虽然.NET平台提供了这样一个互操做的特性,但终究语言是不同的,每一个语言有其特点和差别处,在相互操做的时候就会不免遇到一些例外状况。

好比我在C#中定义了一个基类,类里面包含一个公开的指针类型的成员,我想在vb中继承这个类,并访问这个公开的成员。

 

可是vb语言由于其定位不须要指针,因此并无C#中如int*这样的指针类型,因此在vb中访问一个该语言不支持的类型会报错的,会提示:字段的类型不受支持。

再好比,C#语言中,对类名是区分大小写的,我在C#中定义了两个类,一个叫BaseBusiness,另外一个叫baseBusiness。我在vb中去继承这个BaseBusiness类。

 

如图,在vb中访问这个类会报错的,报:"BaseBusiness"不明确,这是由于在vb中对类名是不区分大小写的。在vb中,它认为它同时访问了两个如出一辙的类,因此按照vb的规则这是不合理的。那么为了在vb调用c#的程序集中避免这些因语言的差别性而致使的错误,在编写c#代码的时候 就应该提早知道vb中的这些规则,来应付式的开发。 

可是,若是我想不只仅局限于C#和VB,我还想我编写的代码在.Net平台上通用的话,那么我还必须得知道.NET平台支持的每一种语言和我编写代码所使用的语言的差别,从而在编写代码中避免这些。

这几年编程语言层出不穷,在未来.NET可能还会支持更多的语言,若是说对一个开发者而言掌握全部语言的差别处这是不现实的,因此.NET专门为此参考每种语言并找出了语言间的共性,而后定义了一组规则,开发者都遵照这个规则来编码,那么代码就能被任意.NET平台支持的语言所通用。
而与其说是规则,不如说它是一组语言互操做的标准规范,它就是公共语言规范 - Common Language Specification ,简称CLS

 

 CLS从类型、命名、事件、属性、数组等方面对语言进行了共性的定义及规范。这些东西被提交给欧洲计算机制造联合会ECMA,称为:共同语言基础设施。

就以类型而言,CLS定义了在C#语言中符合规范的类型和不符合的有:

 

固然,就编码角度而言,咱们不是必需要看那些详略的文档。为了方便开发者开发,.NET提供了一个特性,名叫:CLSCompliantAttribute,代码被CLSCompliantAttribute标记后,若是你写的代码不符合CLS规范的话,编译器就会给你一条警告。

 

 

值得一提的是,CLS规则只是面向那些公开可被其它程序集访问的成员,如public、继承的protected,对于该程序集的内部成员如Private、internal则不会执行该检测规则。也就是说,所适应的CLS听从性规则,仅是那些公开的成员,而非私有实现。

 

那么有没有那种特殊状况,好比我经过反射技术来访问该程序集中,当前语言并不拥有的类型时会发生什么状况呢?

答案是能够尝试的,如用vb反射访问c#中的char*指针类型,即便vb中没有char*这种等价的指针类型,但mscorlib提供了针对指针类型的 Pointer 包装类供其访问,能够从运行时类携带的类型名称看到其本来的类型名。

 

能够看到,该类中的元素是不符合CLS规范的。

CLS异常

提到特殊状况,还要说的一点就是异常处理。.NET框架组成中定义了异常类型系统,在编译器角度,全部catch捕获的异常都必须继承自System.Exception,若是你要调用一个 由不遵循此规范的语言 抛出其它类型的异常对象(C++容许抛出任何类型的异常,如C#调用C++代码,C++抛出一个string类型的异常),在C#2.0以前Catch(Exception)是捕捉不了的,但以后的版本能够。
在后续版本中,微软提供了System.Runtime.CompilerServices.RuntimeWrappedException异常类,将那些不符合CLS的包含Exception的对象封装起来。而且能够经过RuntimeCompatibilityAttribute特性来过滤这些异常。
RuntimeWrappedException :https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.runtimewrappedexception?view=netframework-4.7.2

那么,这个段落总结一下,什么是CLS呢?

在面向.NET开发中,编写跨语言组件时所遵循的那些共性,那些规范就叫作 Common Langrage Specification简称 CLS,公共语言规范 
官方CLS介绍:https://docs.microsoft.com/zh-cn/dotnet/standard/language-independence-and-language-independent-components

什么是CTS?

若是理解了什么是CLS的话,那么你将很轻松理解什么是CTS。
假设你已经围绕着封装 继承 多态 这3个特性设计出了多款面向对象的语言,你发现你们都是面向对象,都能很好的将现实中的对象模型表达出来。除了语法和功能擅长不一样,语言的定义和设计结构其实都差很少一回事。

好比,现实中你看到了一辆小汽车,这辆车里坐着两我的,那么如何用这门语言来表达这样的一个概念和场面?
首先要为这门语言横向定义一个“类型”的概念。接下来在程序中就能够这样表示:有一个汽车类型,有一我的类型,在一个汽车类型的对象内包含着两我的类型的对象,由于要表达出这个模型,你又引入了“对象”的概念 。而如今,你又看到,汽车里面的人作出了开车的这样一个动做,由此你又引入了“动做指令”这样一个概念。
接着,你又恍然大悟总结出一个定理,不管是什么样的“类型”,都只会存在这样一个特征,即活着的 带生命特征的(如人) 和 死的 没有生命特征的(如汽车) 这二者中的一个。最后,随着思想模型的成熟,你发现,这个“类型”就至关于一个富有主体特征的一组指令的集合。
好,而后你开始照葫芦画瓢。你参考其它程序语言,你发现你们都是用class来表示类的含义,用struct表示结构的含义,用new来表示 新建一个对象的含义,因而,你对这部分功能的语法也使用class和new关键字来表示。而后你又发现,他们还用不少关键字来更丰富的表示这些现实模型,好比override、virtual等。因而,在不断的思想升级和借鉴后,你对这个设计语言过程当中思想的变化仔细分析,对这套语言体系给抽象概括,最终总结出一套体系。

因而你对其它人这样说,我总结出了一门语言不少必要的东西如两种主要类别:值类别和引用类别,五个主要类型:类、接口、委托、结构、枚举,我还规定了,一个类型能够包含字段、属性、方法、事件等成员,我还指定了每种类型的可见性规则和类型成员的访问规则,等等等等,只要按照我这个体系来设计语言,设计出来的语言它可以拥有不少不错的特性,好比跨语言,跨平台等,C#和VB.net之因此可以这样就是由于这两门语言的设计符合我这个体系。

那么,什么是CTS呢?

当你须要设计面向.Net的语言时所须要遵循一个体系(.Net平台下的语言都支持的一个体系)这个体系就是CTS(Common Type System 公共类型系统),它包括但不限于:

  • 创建用于跨语言执行的框架。

  • 提供面向对象的模型,支持在 .NET 实现上实现各类语言。

  • 定义处理类型时全部语言都必须遵照的一组规则(CLS)。

  • 提供包含应用程序开发中使用的基本基元数据类型(如 Boolean、Byte、Char 等)的库。

上文的CLS是CTS(Common Type System 公共类型系统)这个体系中的子集。
一个编程语言,若是它可以支持CTS,那么咱们就称它为面向.NET平台的语言。
官方CTS介绍: https://docs.microsoft.com/zh-cn/dotnet/standard/common-type-system 

微软已经将CTS和.NET的一些其它组件,提交给ECMA以成为公开的标准,最后造成的标准称为CLI(Common Language Infrastructure)公共语言基础结构。
因此有的时候你见到的书籍或文章有的只提起CTS,有的只提起CLI,请不要奇怪,你能够宽泛的把他们理解成一个意思,CLI是微软将CTS等内容提交给国际组织计算机制造联合会ECMA的一个工业标准。

什么是类库?

在CTS中有一条就是要求基元数据类型的类库。咱们先搞清什么是类库?类库就是类的逻辑集合,你开发工做中你用过或本身编写过不少工具类,好比搞Web的常常要用到的 JsonHelper、XmlHelper、HttpHelper等等,这些类一般都会在命名为Tool、Utility等这样的项目中。 像这些类的集合咱们能够在逻辑上称之为 "类库",好比这些Helper咱们统称为工具类库。

什么是基础类库BCL?

当你经过VS建立一个项目后,你这个项目就已经引用好了经过.NET下的语言编写好的一些类库。好比控制台中你直接就能够用ConSole类来输出信息,或者using System.IO 便可经过File类对文件进行读取或写入操做,这些类都是微软帮你写好的,不用你本身去编写,它帮你编写了一个面向.NET的开发语言中使用的基本的功能,这部分类,咱们称之为BCL(Base Class Library), 基础类库,它们大多都包含在System命名空间下。

基础类库BCL包含:基本数据类型,文件操做,集合,自定义属性,格式设置,安全属性,I/O流,字符串操做,事件日志等的类型

什么是框架类库FCL?

有关BCL的就不在此一一类举。.NET之大,发展至今,由微软帮助开发人员编写的类库愈来愈多,这让咱们开发人员开发更加容易。由微软开发的类库统称为:FCL,Framework Class Library ,.NET框架类库,我上述所表达的BCL就是FCL中的一个基础部分,FCL中大部分类都是经过C#来编写的。

在FCL中,除了最基础的那部分BCL以外,还包含咱们常见的 如 : 用于网站开发技术的 ASP.NET类库,该子类包含webform/webpage/mvc,用于桌面开发的 WPF类库、WinForm类库,用于通讯交互的WCF、asp.net web api、Web Service类库等等

什么是基元类型?

像上文在CTS中提到了 基本基元数据类型,你们知道,每门语言都会定义一些基础的类型,好比C#经过 int 来定义整型,用 string 来定义 字符串 ,用 object 来定义 根类。当咱们来描述这样一个类型的对象时能够有这两种写法,如图:

 

咱们能够看到,上边用首字母小写的蓝色体string、object能描述,用首字母大写的浅蓝色String、Object也能描述,这两种表述方式有何不一样?

要知道,在vs默认的颜色方案中,蓝色体 表明关键字,浅蓝色体 表明类型。
那么这样也就意味着,由微软提供的FCL类库里面 包含了 一些用于描述数据类型的 基础类型,不管咱们使用的是什么语言,只要引用了FCL,咱们均可以经过new一个类的方式来表达数据类型。
如图:

 

用new来建立这些类型的对象,但这样就太繁琐,因此C#就用 int关键字来表示System.Int32,用 string关键字来表示 System.String等,因此咱们才能这样去写。

 

像这样被表述于编译器直接支持的类型叫作基元类型,它被直接映射于BCL中具体的类。

下面是部分面向.NET的语言的基元类型与对应的BCL的类别图 :

 

System.Object的意义

提及类型,这里要说CTS定义的一个很是重要的规则,就是类与类之间只能单继承,System.Object类是全部类型的根,任何类都是显式或隐式的继承于System.Object。

    System.Object定义了类型的最基本的行为:用于实例比较的Equals系列方法、用于Hash表中Hash码的GetHashCode、用于Clr运行时获取的类型信息GetType、用于表示当前对象字符串的ToString、用于执行实例的浅复制MemberwiseClone、用于GC回收前操做的析构方法Finalize 这6类方法。

因此 Object不只是C#语言的类型根、仍是VB等全部面向.NET的语言的类型根,它是整个FCL的类型根。

   固然,CTS定义了单继承,不少编程语言都知足这个规则,但也有语言是例外,如C++就不作继承限制,能够继承多个,C++/CLI做为C++在对.NET的CLI实现,若是在非托管编码中多继承那也能够,若是试图在托管代码中多继承,那就会报错。我前面已经举过这样特殊状况的例子,这也在另外一方面反映出,各语言对CTS的支持并非都如C#那样全面的,咱们只需明记一点:对于符合CTS的那部分天然就按照CTS定义的规则来。 任何可遵循CTS的类型规范,同时又有.NET运行时的实现的编程语言就能够成为.NET中的一员。

计算机是如何运行程序的?

接下来我要说什么是.NET的跨平台,并解释为何可以跨语言。不过要想知道什么是跨平台,首先你得知道一个程序是如何在本机上运行的。

什么是CPU

CPU,全称Central Processing Unit,叫作中央处理器,它是一块超大规模的集成电路,是计算机组成上必不可少的组成硬件,没了它,计算机就是个壳。
不管你编程水平怎样,你都应该先知道,CPU是一台计算机的运算核心和控制核心,CPU从存储器或高速缓冲存储器中取出指令,放入指令寄存器,并对指令译码,执行指令。
咱们运行一个程序,CPU就会不断的读取程序中的指令并执行,直到关闭程序。事实上,从电脑开机开始,CPU就一直在不断的执行指令直到电脑关机。

什么是高级编程语言

在计算机角度,每一种CPU类型都有本身能够识别的一套指令集,计算机无论你这个程序是用什么语言来编写的,其最终只认其CPU可以识别的二进制指令集。
在早期计算机刚发展的时代,人们都是直接输入01010101这样的没有语义的二进制指令来让计算机工做的,可读性几乎没有,没人愿意直接编写那些没有可读性、繁琐、费时,易出差错的二进制01代码,因此后来才出现了编程语言。

编程语言的诞生,使得人们编写的代码有了可读性,有了语义,与直接用01相比,更有利于记忆。
而前面说了,计算机最终只识别二进制的指令,那么,咱们用编程语言编写出来的代码就必需要转换成供机器识别的指令。
就像这样:

code: 1+2 function 翻译方法(参数:code) 
{ 
    ... 
    "1"=>"001"; 
    "2"=>"002";    "+"=>"000"; 
    return 能让机器识别的二进制代码; 
} 
call 翻译方法("1+2") => "001 000 002"

因此从一门编程语言所编写的代码文件转换成能让本机识别的指令,这中间是须要一个翻译的过程。
而咱们如今计算机上是运载着操做系统的,光翻译成机器指令也不行,还得让代码文件转化成可供操做系统执行的程序才行。
那么这些步骤,就是编程语言所对应的编译环节的工程了。这个翻译过程是须要工具来完成,咱们把它叫作 编译器。

不一样厂商的CPU有着不一样的指令集,为了克服面向CPU的指令集的难读、难编、难记和易出错的缺点,后来就出现了面向特定CPU的特定汇编语言, 好比我打上这样的x86汇编指令 mov ax,bx ,而后用上用机器码作的汇编器,它将会被翻译成 1000100111011000 这样的二进制01格式的机器指令.

不一样CPU架构上的汇编语言指令不一样,而为了统一一套写法,同时又不失汇编的表达能力,C语言就诞生了。
用C语言写的代码文件,会被C编译器先转换成对应平台的汇编指令,再转成机器码,最后将这些过程当中产生的中间模块连接成一个能够被操做系统执行的程序。

那么汇编语言和C语言比较,咱们就不须要去阅读特定CPU的汇编码,我只须要写通用的C源码就能够实现程序的编写,咱们用将更偏机器实现的汇编语言称为低级语言,与汇编相比,C语言就称之为高级语言。

在看看咱们C#,咱们在编码的时候都不须要过于偏向特定平台的实现,翻译过程也基本遵循这个过程。它的编译模型和C语言相似,都是属于这种间接转换的中间步骤,故而可以跨平台。
因此就相似于C/C#等这样的高级语言来讲是不区分平台的,而在于其背后支持的这个 翻译原理 是否能支持其它平台。

什么是托管代码,托管语言,托管模块?

做为一门年轻的语言,C#借鉴了许多语言的长处,与C比较,C#则更为高级。
每每一段简小的C#代码,其功能却至关于C的一大段代码,而且用C#语言你几乎不须要指针的使用,这也就意味着你几乎不须要进行人为的内存管控与安全考虑因素,也不须要多懂一些操做系统的知识,这让编写程序变得更加轻松和快捷。

若是说C#一段代码能够完成其它低级语言一大段任务,那么咱们能够说它特性丰富或者类库丰富。而用C#编程不须要人为内存管控是怎么作到的呢?
    .NET提供了一个垃圾回收器(GC)来完成这部分工做,当你建立类型的时候,它会自动给你分配所须要的这部份内存空间。就至关于,有一个专门的软件或进程,它会读取你的代码,而后当你执行这行代码的时候,它帮你作了内存分配工做。 这部分本该你作的工做,它帮你作了,这就是“托管”的概念。好比现实中 托管店铺、托管教育等这样的别人替你完成的概念。

所以,C#被称之为托管语言。C#编写的代码也就称之为托管代码,C#生成的模块称之为托管模块等。(对于托管的资源,是不须要也没法咱们人工去干预的,但咱们能够了解它的一些机制原理,在后文我会简单介绍。)

只要有比较,就会产生概念。那么在C#角度,那些脱离了.NET提供的诸如垃圾回收器这样的环境管制,就是对应的 非托管了。

非托管的异常

咱们编写的程序有的模块是由托管代码编写,有的模块则调用了非托管代码。在.NET Framework中也有一套基于此操做系统SEH的异常机制,理想的机制设定下咱们能够直接经过catch(e)或catch来捕获指定的异常和框架设计人员容许咱们捕获的异常。

而异常类型的级别也有大有小,有小到能够直接框架自己或用代码处理的,有大到须要操做系统的异常机制来处理。.NET会对那些能让程序崩溃的异常类型给进行标记,对于这部分异常,在.NET Framework 4.0以前容许开发人员在代码中本身去处理,但4.0版本以后有所变动,这些被标记的异常默认不会在托管环境中抛出(即没法catch到),而是由操做系统的SEH机制去处理。 
不过若是你仍然想在代码中捕获处理这样的异常也是能够的,你能够对须要捕获的方法上标记[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute]特性,就能够在该方法内经过catch捕获到该类型的异常。你也能够经过在配置文件中添加运行时节点来对全局进行这样的一个配置:

HandleProcessCorruptedStateExceptions特性:https://msdn.microsoft.com/zh-cn/library/azure/system.runtime.exceptionservices.handleprocesscorruptedstateexceptionsattribute.aspx SEHException类:https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.sehexception(v=vs.100).aspx 处理损坏状态异常博客专栏: https://msdn.microsoft.com/zh-cn/magazine/dd419661.aspx

相关文章
相关标签/搜索