澳门新葡亰平台官网NET面试题系列,通俗易懂

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

很明显,CLS是CTS的一个子集,而且是最小的子集。

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

  • 张子阳

目录

.NET框架基础知识(1)

参考资料:

  • (非常经典的一篇文章)
  • 精通C# (第六版)
  • CLR via C# (第三版)

.NET和C#是什么关系

1 术语

面试出现频率:从来没人问过。事实上我都不知道怎么问,考背书吗?倒是可以问问知不知道现在.NET最新版本是什么,考察面试者是否对新技术足够敏感。

重要程度:3/10

需要理解的程度:知道这些缩写(CLR,BCL,FCL,CTS,CLS)各代表什么即可。仔细读一遍

跨语言和跨平台是什么

 

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

1.1什么是.NET框架?在各个平台版本中,有什么值得强调的更新?

.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再将其翻译为机器码。

 

澳门新葡亰平台官网 1                       

 

甲骨文公司的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。

澳门新葡亰平台官网 2

.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的一个子集。

 

  • CLS异常

1.2 基础类库(BCL)

Base Class Library (BCL) 是微软所提出的一组标准库,可提供给.NET
Framework所有语言使用。随着 Windows 以及.NET Framework 的成长,BCL
已近乎成为在.NET上的 Windows
API。mscorlib.dll程序集几乎就是基础类库的代名词。

当安装.NET
Framework时,所有的基础类库被部署到全局程序集缓存(GAC)。它的位置一般在C:Windowsassembly。所以你不需要在你的工程中手动引用任何的基础类库,它们会被自动引用。如果你从GAC中删除了mscorlib.dll,你的IDE将变成一个什么都不懂的白痴。因为没有mscorlib.dll,意味着没有基础类库,没有整型,字符串,控制台…你什么都做不了。

部分mscorlib.dll包括的命名空间:

  • System:.NET Framework 类库中最基底的服务,提供应用程序域
    (Application Domain),数据类型,I/O 以及其他类库的基础。
  • System.Collections:提供非泛型数据结构以及集合对象的支持,其中
    System.Collections.Generic中包括所有的泛型数据结构。
  • System.Configuration:提供 .NET 应用程序在配置设置上的支持。
  • System.Data:ADO.NET 的组成类库,为数据访问功能的核心功能。
  • System.Drawing:提供 .NET
    的绘图能力,包含基本位图处理以及视频与色彩处理,打印支持也由本名字空间提供,此名字空间包装了大多数的
    GDI 以及 GDI+ 的 API。
  • System.IO:提供数据流与文件读写的支持
  • System.Net:.NET 中的网络功能
  • System.Reflection:反射
  • System.Diagnostics:.NET
    中提供系统诊断,除错,追踪与运行外部进程的能力
  • System.ServiceModel:WCF 的组成类库,于 .NET Framework 3.0 时出现。
  • System.Text:对文字,编码以及正规表达式的支持。
  • System.Threading:线程控制
  • System.Windows.Forms: Windows Forms 的组成类库,包装了 Win32
    用户界面,视窗,共用控件,以及 Shell 的基础 API,以提供设计 Windows
    应用程序用户界面所需的支持。
  • System.Windows:WPF 的组成类库,于 .NET Framework 3.0 时出现。
  • System.Web:ASP.NET 的组成类库,令工程可以和 IIS 服务器交互,XML Web
    Service 开发的基本支持也由本类别提供。ASP.NET
    Core中消失(如果你不打算用IIS做服务器的容器,则你不需要这个类库)。
  • System.Xml:XML 解析器
  • System.Linq,System.Xml.Linq:LINQ 的核心类库,System.Linq 是 LINQ
    to Object,而 System.Xml.Linq 则是 LINQ to XML。

然而在C:Program Files (x86)Reference
AssembliesMicrosoftFramework.NETFrameworkv4.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。源码在

什么是CTS?

1.3 框架类库(FCL)

作为一名.NET程序员,每天都要打交道的就是FCL了(框架类库)。BCL是FCL的一个子集。简单来说FCL除了BCL的那部分,就是我们要引用的外部参考。

 

什么是类库?

1.4 CTS(公共类型系统)和CLS(公共语言规范)

简单的说,CTS就是说话的语法和规范。你可以理解为,英语是一种语言,英语的CTS(至少绝大一部分)就是“实用英语语法(张道真)”这本书。如果C#没了语法,那就没有class,没有接口,变成了伪码。

参考资料中的第一个链接讲的很好,我就在这里总结一下吧:

  1. CTS是一套语法。类似“英语语法”。它规定了一套约束,例如英语规定所有的字词都是由26个字母组成的(以及其他很多规则)。服从这套语法的语言都可以被看成是英语的某种方言,例如中古英语,现代英语都是英语,而汉语不符合字词由字母组成,所以它不是英语。同理所有服从CTS的语言,都可以被看成.NET框架的语言。
  2. CTS中定义了类型,允许它有属性,字段,方法等。
  3. .NET框架的众多语言各自实现了CTS的一部分功能。做一个不太恰当的类比,C#可以被认为是“美国英语”,F#是“英国英语”而VB是“印度英语”等。他们是英语的各种方言。他们共享一套相同的词汇表,但也各有各的特点。例如颜色在英国英语中的拼写是colour,美国英语则是color。
  4. 由于.NET框架的众多语言在编译时都要转换为IL,因此IL实现的CTS功能是它们的并集,也就是CTS全部的功能。你可以理解为,虽然.NET框架语言那么多,但一编译了之后,就成了一种语言。
  5. .NET框架的众多语言分享CTS的一小部分功能,这部分功能称为CLS(Common
    Language
    Specification,公共语言规范)。这是这些语言(的程序集)可以相互使用的前提。如果你创建一个新语言,其实现了CTS的一部分功能,但不包括CLS,那你的语言就不能被其他.NET框架的语言(的程序集)使用。如果你创建的语言甚至不符合CTS,例如你在词汇表中加入了汉字,那不好意思,你创建的语言不能叫英语。

很明显,CLS是CTS的一个子集,而且是最小的子集。(最小功能集)

澳门新葡亰平台官网 3

图片来自CLR via C#。

  • 什么是基础类库BCL?
  • 什么是框架类库FCL?

 

什么是基元类型?

1.5 为什么说.NET是平台无关的?

.NET程序集可以在非微软操作系统如Mac
OS,各种版本的Linux,以及iOS和Android移动设备上开发和执行。.NET的平台无关性主要体现为:.NET程序集可以在任何的平台上运行,不管是Windows,还是Mac,只要这个平台拥有将IL转换为机器码,以及加载其他相关程序集的能力(即CLR),而任何机器都可以运行机器码。这类似于Java的虚拟机,只要平台装了Java虚拟机,则这个平台就可以运行Java程序。

System.Object的意义

 

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

1.6 CLR(公共语言运行时)

CLR是让程序执行所需的外部服务的集合,类似Java需要JVM虚拟机才可以运行。

它的核心功能(比如即时编译,内存管理,程序集加载,安全性,异常处理和线程同步)可由面向CLR的所有语言使用。例如,CLR允许创建线程,所以面向CLR的所有语言都能创建线程。

CLR是.NET的运行基础,管理.NET程序集的执行。它运行于Windows之上,很多功能仅仅是Windows上的一个wrapper,例如线程,内存管理等,这些实际上是Windows在管理。但JIT则是它独有的,如果没有它,就不能把IL变成机器码,计算机也就不认识C#,你也就不能运行C#程序。

在开始运行.NET程序之前,编译器将代码转换为IL。IL代码并不能直接运行,CLR将真正需要用到的程序集导入内存,读取元数据,接着为类型开辟内存空间,执行所有需要的安全检查,并最终运行代码:

  • CLR找到代码中拥有Main方法的类型并且加载这个类型。CLR中一个名为Class
    loader(类加载程序)的组件负责这项工作。它会从GAC、配置文件、程序集元数据中寻找这个类型,然后将它的类型信息加载到内存中的数据结构中。在Class
    loader找到并加载完这个类型之后,它的类型信息会被缓存起来,这样就无需再次进行相同的过程。当然,如果这个类型引用了其他的类型,则会导致一连串的程序集加载,这将定义程序代码执行的环境(类似Java的JVM)。注意即使工程很大,有几百个程序集,CLR不会全部加载,只会在真正用到该程序集的时候才加载。
  • 验证。在CLR中,还存在一个验证程序(verifier),该验证程序的工作是在运行时确保代码是类型安全的。它主要校验两个方面,一个是元数据是正确的,一个是IL代码必须是类型安全的,类型的签名必须正确。这是早期绑定验证,验证在运行时之前发生。对于动态类型,此时不做任何检查。
  • 即时编译。(此时就从编译时过渡到了运行时)这一步就是将托管的IL代码编译为可以执行的机器代码的过程,由CLR的即时编译器(JIT
    Complier)完成。即时编译只有在方法的第一次调用时发生。类型加载程序(Class
    loader)会为每个方法插入一个存根。在调用方法时,CLR会检查方法的存根,如果存根为空,则执行JIT编译过程,并将该方法被编译后的本地机器代码地址写入到方法存根中。当第二次对同一方法进行调用时,会再次检查这个存根,如果发现其保存了本地机器代码的地址,则直接跳转到本地机器代码进行执行,无需再次进行JIT编译。JIT编译还会优化本地的代码。

在程序运行时,CLR还负责:

  • 异常处理
  • 内存管理与垃圾回收
  • 线程管理(线程池)

托管代码是必须在CLR下执行的代码,而非托管代码则不需要CLR的支持就可以运行。CLR本身用于管理托管代码,因此它是由非托管代码编写的,并不是一个包含了托管代码的程序集,也不能使用IL
DASM进行查看。它位于C:%SystemRoot%Microsoft.NETFramework版本号下,视安装的机器不同有两个版本,一个是工作站版本的mscorwks.dll,一个是服务器版本的mscorsvr.dll。wks和svr分别代表workstation和server。

CLR via
C#这本书选择通过C#作为视角,讨论CLR的各种功能。通过对这本书的阅读,你会对一些实际由CLR进行管理的行为例如垃圾回收,线程管理有更加深刻的认识。

  • 什么是CPU?
  • 什么是高级编程语言?

 

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

2. 编译:IL与JIT

面试出现频率:低。不排除部分IL专家会试探性问你一些IL命令,但我相信你答不出来他们也不会在意。学了IL和没学,一般人看不出来区别,学了IL,也不意味着你就很厉害。个人认为,学IL唯一的用处就在于证明你看到的书上写的各种结论,或者验证一些性能方面的想法。你可以参看这篇文章:

重要程度:3/10,常识性了解即可

需要理解的程度:知道IL是中间代码,知道JIT的优点(带缓存的编译),以及它可能会对你的代码进行优化。

  • 非托管的异常

 

什么是CLR,.NET虚拟机?

2.1 什么是IL(CIL)?如何获得IL代码?

在.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系列:

什么是CLR宿主进程,运行时主机?

 

Windows系统自带.NET
Framework

2.2 什么是JIT?还有什么其他编译方式?何时使用到JIT?

即时编译(英语:Just-in-time
compilation)是动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态编译。静态编译的程序在执行前全部被翻译为机器码,而动态编译执行的则是一句句,边运行边翻译。

即时编译则混合了这二者,一句句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。

CLR的JIT负责将IL编译成机器码。
当程序编译成程序集之后,CLR加载任何需要用到的其他程序集,并开始使用JIT将CIL编译为机器码。JIT编译器会在方法的首次调用时,从类型的元数据中查找方法,并进行检查,例如检查类型是否安全。如果出现了问题,则触发运行时错误。以后对方法的所有调用都以本地代码的形式全速运行,无须重新检查。

.NET Framework
4.0.30319

 

  • .NET
    Framework4.X覆盖更新
  • 如何确认本机安装了哪些.NET
    Framework和对应CLR的版本?

2.3 本地代码的优化

CLR的JIT编译器会对本地代码进行优化。例如字符串驻留中对常量字符串相加的优化。和没有优化相比,优化之后的代码将获得更出色的性能。但过度的优化可能会出现问题,在CLR
via C#的易失构造中,作者举了一个例子。

澳门新葡亰平台官网 4澳门新葡亰平台官网 5

 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     }

View Code

如果使用f5呼叫出Visual
Studio的调试模式,则程序会像预期的那样正常运行直到结束。使用调试器会造成JIT编译器在Debug模式进行编译,它生成未优化的代码,目的是方便你进行单步调试。如果是选择了x86的Release模式进行编译:

澳门新葡亰平台官网 6

它将会生成被CLR优化的代码。值得一提的是,x86编译器是一个更成熟的编译器,执行优化比x64更大胆。x64不会执行上面所说的特定的优化。在再次用f6进行编译之后,用ctrl+f5运行程序,程序将会陷入无限循环。

澳门新葡亰平台官网 7

注意:必须用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文件。例如,你写了一个小的控制台程序给别人用,那么你不需要把bindebug里面所有的文件都拷贝给别人,你只需要程序本身,必要的dll和config文件即可。

什么是程序集

用csc.exe进行编译

.NET程序执行原理

  • JIT编译
  • AOT编译

程序集的规则

  • 程序集的加载方式
  • 强名称程序集
  • 程序集搜索规则
  • 项目的依赖顺序
  • 为什么Newtonsoft.Json版本不一致?
  • 如何在编译时加载两个相同的程序集
  • 如何同时调用两个两个相同命名空间和类型的程序集?
  • 共享程序集GAC
  • 延伸

应用程序域

  • 跨边界访问
  • AppDomain和AppPool

内存

  • 堆栈和堆的区别
  • 线程堆栈
  • 为什么值类型存储在栈上
  • 托管堆模型
  • 选class还是struct
  • GC管理器
  • 弱引用、弱事件
  • GC堆回收
  • 垃圾回收对性能的影响
  • 性能建议

.NET程序执行图

.NET的安全性

  • 基于角色的安全性
  • 代码访问安全性

什么是.NET

  • 什么是.NET
    Framework

    • 如何在VS中调试.NET
      Framework源代码
  • 什么是.NET
    Core
  • 什么是.NET
    Standard
  • .NET官方开源项目链接

Visual Studio

  • sln解决方案
  • 项目模板
  • csproj工程文件
  • 项目属性杂项
  • IntelliTrace智能追溯
  • 链接

建议

.NET和C#是什么关系

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

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

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中当做自家写的类一样正常使用。

比如我在vb中写了一个针对String的首字母大写的扩展方法,将其编译后的dll引用至C#项目中。
澳门新葡亰平台官网 8

在C#项目中,可以像自身代码一样正常使用来自vb这个dll的扩展方法。

澳门新葡亰平台官网 9

现在有那么多面向对象语言,但不是所有编程语言都能这样直接互操作使用,而.NET平台支持的C#和VB之所以能这样无缝衔接,先读而后知,后文将会介绍缘由。不过虽然.NET平台提供了这样一个互操作的特性,但终究语言是不一样的,每个语言有其特色和差异处,在相互操作的时候就会难免遇到一些例外情况。

比如我在C#中定义了一个基类,类里面包含一个公开的指针类型的成员,我想在vb中继承这个类,并访问这个公开的成员。
澳门新葡亰平台官网 10澳门新葡亰平台官网 11

但是vb语言因为其定位不需要指针,所以并没有C#中如int*这样的指针类型,所以在vb中访问一个该语言不支持的类型会报错的,会提示:字段的类型不受支持。

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

澳门新葡亰平台官网 12澳门新葡亰平台官网 13

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

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

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

澳门新葡亰平台官网 14

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

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

澳门新葡亰平台官网 15澳门新葡亰平台官网 16

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

 澳门新葡亰平台官网 17

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

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

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

澳门新葡亰平台官网 19

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

CLS异常

提到特殊情况,还要说的一点就是异常处理。.NET框架组成中定义了异常类型系统,在编译器角度,所有catch捕获的异常都必须继承自System.Exception,如果你要调用一个
由不遵循此规范的语言
抛出其它类型的异常对象(C++允许抛出任何类型的异常,如C#调用C++代码,C++抛出一个string类型的异常),在C#2.0之前Catch(Exception)是捕捉不了的,但之后的版本可以。
在后续版本中,微软提供了System.Runtime.CompilerServices.RuntimeWrappedException异常类,将那些不符合CLS的包含Exception的对象封装起来。并且可以通过RuntimeCompatibilityAttribute特性来过滤这些异常。
RuntimeWrappedException

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

在面向.NET开发中,编写跨语言组件时所遵循的那些共性,那些规范就叫做
Common Langrage Specification简称 CLS,公共语言规范
官方CLS介绍:

什么是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介绍:

微软已经将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 来定义
根类。当我们来描述这样一个类型的对象时可以有这两种写法,如图:

澳门新葡亰平台官网 20

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

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

澳门新葡亰平台官网 21

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

澳门新葡亰平台官网 22

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

下面是部分面向.NET的语言的基元类型与对应的BCL的类别图 :
澳门新葡亰平台官网 23

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提供的诸如垃圾回收器这样的环境管制,就是对应的
非托管了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注