很明显,CLS是CTS的一个子集,而且是最小的子集。 - 张子阳
参考资料:
面试出现频率:从来没人问过。事实上我都不知道怎么问,考背书吗?倒是可以问问知不知道现在.NET最新版本是什么,考察面试者是否对新技术足够敏感。
重要程度:3/10
需要理解的程度:知道这些缩写(CLR,BCL,FCL,CTS,CLS)各代表什么即可。仔细读一遍http://www.tracefact.net/CLR-and-Framework/DotNet-Framework.aspx
.NET框架是以一种采用系统虚拟机(即CLR)运行的,面向CLR的编程平台,以CLR为基础。.NET的基础类库运行于CLR之上(类比Java的虚拟机),作为其他各种功能的基石。.NET框架支持多种语言(C#、F#、VB.NET、C++、Python等)的开发。它的前身是Windows DNA。现在.NET框架的扩展性甚至超过Java,其的Mono为Mac OS提供了支持,Xamarin可媲美安卓开发,可以在任何手机上开发。
.NET框架是开源的。它的代码在https://github.com/dotnet/。如果你的commit有幸被接受,即使改动有多么微小,也是无上的荣耀,你绝对应该把它写到你简历的第一行,这个成就可以和“为Linux内核优化做过贡献”相比,那可比曾经在BAT做过几年的经历牛逼多了。
所有.NET支持的语言编写出来的程序,在支持.NET的编译器编译之后,会先产出程序集,其主要内容是IL和元数据。之后,JIT再将其翻译为机器码。
甲骨文公司的Java EE是.NET平台的竞争对手之一。
.NET框架现在已经出到了版本4.6.1。在3.0之前,.NET框架的Web解决方案是ASP.NET(Webform & MVC),数据库连接为ADO.NET(支持过去的ODBC,OLE等,并支持SQL Server和Oracle),Windows Form则作为Windows下的应用解决方案。
.NET最重大的一个版本更新是3.0,其中,提出了WCF(统一了过去Web服务混乱的形式,形成了一个统一的格式,并采用SOAP),WPF(作为Windows form的增强版)以及WF。
.NET3.5集成了LINQ。另外Entity Framework取代ADO.NET,它对应VS2008。
.NET4.0提出了任务并行库和PLINQ。
.NET 5 (即.NET Core 1.0)在2016年6月27日推出。是次推出伴随着ASP.NET Core (即ASP.NET 6)和Entity Framework 7。这些产品将支持Windows,OS X和Linux三种操作系统。
新版本的.NET项目使用.json文件代替了过去的.xxproj,.sln和.suo文件,这符合目前的主流,即用json代替XML。新版本的.NET框架要传输给我们的理念是:这是一个跨平台的,开源的框架。一切都是依赖注入,一切都是nuget,开发彻底组件化,能解耦的全都解耦。ASP.NET Core彻底摆脱了System.Web这个顽疾,在其中,我们甚至连MVC都是注入进去的。如果想得到什么组件,要么通过依赖注入,要么就使用nuget。永远不要手动add reference,目前我知道的唯一的例外是System.Configuration。当你和团队其他人并行开发系统的不同模块时,你们可以用nuget互相得到对方模块中的工程。Nuget相比add reference,更不容易出错,界面更友好,且不会轻易陷入dll陷阱。
经过.NET牌编译器编译之后的程序集有两种形态:类库(.dll)形态和可执行文件(.exe)形态。.NET自带了很多类库,统称为FCL。BCL是FCL的一个子集。
Base Class Library (BCL) 是微软所提出的一组标准库,可提供给.NET Framework所有语言使用。随着 Windows 以及.NET Framework 的成长,BCL 已近乎成为在.NET上的 Windows API。mscorlib.dll程序集几乎就是基础类库的代名词。
当安装.NET Framework时,所有的基础类库被部署到全局程序集缓存(GAC)。它的位置一般在C:\Windows\assembly。所以你不需要在你的工程中手动引用任何的基础类库,它们会被自动引用。如果你从GAC中删除了mscorlib.dll,你的IDE将变成一个什么都不懂的白痴。因为没有mscorlib.dll,意味着没有基础类库,没有整型,字符串,控制台…你什么都做不了。
部分mscorlib.dll包括的命名空间:
然而在C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\我们还有一个System.dll,这个参考是每次新建工程时VS自动引用的若干参考之一。这个程序集中也有一个System命名空间,它的内容和mscorlib.dll中的不同。可以看到,System这个命名空间存在于不止一个程序集中。这意味着不同的程序集可以共享一个命名空间。
在System.dll中,System类型拥有Uri这个成员,mscorlib.dll中System类型拥有int这个成员(基元类型)。所以我们可以做个试验,如果我们将工程中对System的引用去掉,那么我们就不能定义一个Uri类型的对象。但我们仍然可以使用int类型,因为它虽然也在System这个类型里面,但位于mscorlib.dll中。当你去掉对System的引用时,你仅仅去掉了System.dll和里面的功能,但你没有去掉mscorlib.dll中System类型的功能。
BCL是属于整个.NET框架的,并非某种语言的一个基础类库。例如,C#的string类型的所有功能和定义来源于mscrolib.dll中的System.String,而VB的string类型的功能和定义也来源于相同的地方。基础类库中定义的类型称为基元类型,它也是为.NET框架所有的语言共享。
在.NET Core中,BCL改名换姓变成了Corefx。源码在https://github.com/dotnet/corefx。
作为一名.NET程序员,每天都要打交道的就是FCL了(框架类库)。BCL是FCL的一个子集。简单来说FCL除了BCL的那部分,就是我们要引用的外部参考。
简单的说,CTS就是说话的语法和规范。你可以理解为,英语是一种语言,英语的CTS(至少绝大一部分)就是“实用英语语法(张道真)”这本书。如果C#没了语法,那就没有class,没有接口,变成了伪码。
参考资料中的第一个链接讲的很好,我就在这里总结一下吧:
很明显,CLS是CTS的一个子集,而且是最小的子集。(最小功能集)
图片来自CLR via C#。
.NET程序集可以在非微软操作系统如Mac OS,各种版本的Linux,以及iOS和Android移动设备上开发和执行。.NET的平台无关性主要体现为:.NET程序集可以在任何的平台上运行,不管是Windows,还是Mac,只要这个平台拥有将IL转换为机器码,以及加载其他相关程序集的能力(即CLR),而任何机器都可以运行机器码。这类似于Java的虚拟机,只要平台装了Java虚拟机,则这个平台就可以运行Java程序。
CLR是让程序执行所需的外部服务的集合,类似Java需要JVM虚拟机才可以运行。
它的核心功能(比如即时编译,内存管理,程序集加载,安全性,异常处理和线程同步)可由面向CLR的所有语言使用。例如,CLR允许创建线程,所以面向CLR的所有语言都能创建线程。
CLR是.NET的运行基础,管理.NET程序集的执行。它运行于Windows之上,很多功能仅仅是Windows上的一个wrapper,例如线程,内存管理等,这些实际上是Windows在管理。但JIT则是它独有的,如果没有它,就不能把IL变成机器码,计算机也就不认识C#,你也就不能运行C#程序。
在开始运行.NET程序之前,编译器将代码转换为IL。IL代码并不能直接运行,CLR将真正需要用到的程序集导入内存,读取元数据,接着为类型开辟内存空间,执行所有需要的安全检查,并最终运行代码:
在程序运行时,CLR还负责:
托管代码是必须在CLR下执行的代码,而非托管代码则不需要CLR的支持就可以运行。CLR本身用于管理托管代码,因此它是由非托管代码编写的,并不是一个包含了托管代码的程序集,也不能使用IL DASM进行查看。它位于C:\%SystemRoot%\Microsoft.NET\Framework\版本号下,视安装的机器不同有两个版本,一个是工作站版本的mscorwks.dll,一个是服务器版本的mscorsvr.dll。wks和svr分别代表workstation和server。
CLR via C#这本书选择通过C#作为视角,讨论CLR的各种功能。通过对这本书的阅读,你会对一些实际由CLR进行管理的行为例如垃圾回收,线程管理有更加深刻的认识。
面试出现频率:低。不排除部分IL专家会试探性问你一些IL命令,但我相信你答不出来他们也不会在意。学了IL和没学,一般人看不出来区别,学了IL,也不意味着你就很厉害。个人认为,学IL唯一的用处就在于证明你看到的书上写的各种结论,或者验证一些性能方面的想法。你可以参看这篇文章:http://blog.zhaojie.me/2009/06/my-view-of-il-2-il-shows-little-about-clr.html
重要程度:3/10,常识性了解即可
需要理解的程度:知道IL是中间代码,知道JIT的优点(带缓存的编译),以及它可能会对你的代码进行优化。
在.NET的开发过程中, IL的官方术语是MSIL或CIL(Common Intermediate Language,即公共中间语言)。因此,IL,MSIL和CIL指的是同一种东西。
当使用支持.NET的编译器编译之后,生成.dll或.exe文件。这文件称作.NET程序集,包含IL和元数据。不同语言(例如C#和VB)经过不同编译器(例如C#编译器和VB编译器),编译一段功能相似的代码(区别仅仅在于语法),其IL也基本相似。虽然IL相对C#较为底层,但它仍然是一个十分高级的语言。它并不是汇编语言。
可以通过ildasm(在cmd中运行)工具加载任意的.NET程序集并分析它的内容,包括它所包含的IL代码和元数据。注意,高级语言只公开了CLR的所有功能的一个子集,而IL允许开发人员访问CLR所有的功能。
关于IL的扩展阅读,可参看老赵谈IL系列:
http://blog.zhaojie.me/2009/06/my-view-of-il-1-il-and-asm.html
即时编译(英语:Just-in-time compilation)是动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态编译。静态编译的程序在执行前全部被翻译为机器码,而动态编译执行的则是一句句,边运行边翻译。
即时编译则混合了这二者,一句句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。
CLR的JIT负责将IL编译成机器码。 当程序编译成程序集之后,CLR加载任何需要用到的其他程序集,并开始使用JIT将CIL编译为机器码。JIT编译器会在方法的首次调用时,从类型的元数据中查找方法,并进行检查,例如检查类型是否安全。如果出现了问题,则触发运行时错误。以后对方法的所有调用都以本地代码的形式全速运行,无须重新检查。
CLR的JIT编译器会对本地代码进行优化。例如字符串驻留中对常量字符串相加的优化。和没有优化相比,优化之后的代码将获得更出色的性能。但过度的优化可能会出现问题,在CLR via C#的易失构造中,作者举了一个例子。
1 class Program
2 {
3 private static bool s_stopWorker = false;
4
5 static void Main()
6 {
7 Console.WriteLine("Main: letting worker run for 2 seconds");
8 Thread t = new Thread(Worker);
9 t.Start();
10
11 Thread.Sleep(2000);
12 s_stopWorker = true;
13 Console.WriteLine("Main: waiting for worker to stop");
14 t.Join();
15 }
16
17 private static void Worker(object o)
18 {
19 int x = 0;
20 while (!s_stopWorker)
21 {
22 x++;
23 }
24 Console.WriteLine("Worker: stopped when x = {0}", x);
25 }
26 }
如果使用f5呼叫出Visual Studio的调试模式,则程序会像预期的那样正常运行直到结束。使用调试器会造成JIT编译器在Debug模式进行编译,它生成未优化的代码,目的是方便你进行单步调试。如果是选择了x86的Release模式进行编译:
它将会生成被CLR优化的代码。值得一提的是,x86编译器是一个更成熟的编译器,执行优化比x64更大胆。x64不会执行上面所说的特定的优化。在再次用f6进行编译之后,用ctrl+f5运行程序,程序将会陷入无限循环。
注意:必须用x86+Release编译,然后以非调试模式运行(即Ctrl+F5),才能看到这个效果。问题发生的原因是,x86的编译优化过度。它发现变量s_stopWorker要么为true要么为false。它还发现这个值在worker方法本身中从来没有变化。因此,编译器会生成代码检查s_stopWorker,如果s_stopWorker为true,就显示“Worker: stopped when x = 0”。如果s_stopWorker为false编译器就生成代码进入一个无限循环,并一直递增x。解决的办法是为s_stopWorker加入修饰词volatile。
PDB文件包含了可以令调试器在本地工作的信息。可以这么说:有了PDB文件,本地的debug才成为可能。如果你打算发布Release版本,则不需要该文件。使用Release模式编译的结果中也不包含PDB文件。例如,你写了一个小的控制台程序给别人用,那么你不需要把\bin\debug里面所有的文件都拷贝给别人,你只需要程序本身,必要的dll和config文件即可。