# C#简介

此文是<<C#入门经典>>的读书笔记,也整合了网络上的一些内容。

# .NetFramework相关

.NetFramework是Microsoft为开发应用程序而创建的一个具有革命意义的平台,它是跨平台的,其中Mono是 .Net Framework的开源版本,能运行在Linux上或macOS,而Xamarian是基于Mono在移动平台的实现。此外Microsoft还创建了一个跨平台的开源库 .Net Core。

# .NetFramework内容

它是一个庞大的代码库,可以在客户端和服务器端语言如(C#)中通过OOP来编程,这个库分为多个不同的模块,可以根据需要使用,不同的操作系统可以根据各自特征支持其中的部分或全部模块。

.NetFramework库定义了一些基本类型,称为通用类型系统(Commont Type System,CTS),这些类型有助于 .Net Framework的各种语言之间进行互通操作,这意味着一个模块假如是用F#编写的,那么任何支持的CLI语言比如C#可以使用该模块内的对象和方法,此外.NetFramework还包含.Net公共语言运行库(Common Language Runtime,CLR),负责管理用.Net库开发的应用程序的执行。它们是 .Net跨平台的基础。

# .Net应用场景

在 .Net Standard和可移植类库出现直线,有一个共享项目的概念,在共享项目中,常使用#if,#else和#endif指令来标识代码运行在什么软件或硬件平台上,然后为对应平台加载正确的程序集。这导致当软件或硬件组件发生变化时,需要进行大量的更新,随着面向多个垂直模型和平台的需求增加,需要一种新的解决方案来实现跨平台支持,这就催生了可移植类库(PCL)。

PCL在很大程度上帮助解决了扩展,维护,测试和可支持特性问题,在PCL中创建类时,程序员需要选择面向哪个.Net Framework(Compact,Micro,Silverlight,Core)。如果只在Windows堆栈中进行开发,PCL的效果很好,但是Windows系统的一些功能是它独有的,比如注册表,比如Windows中的AppDomain是进程中的一个隔离层,PCL确实帮助解决了针对多个 Windows垂直模型进行开发的问题,但并没有实现完全地软件和硬件跨平台支持。

这时微软给出的方案是创建 .Net Standard和 .Net Core。 .Net Standard是一组 .Net API,设计目标是用于所有的 .Net垂直模型,它取代了每个分支或框架垂直模型中特定于BCL的实现细节,将所有的.Net Framework垂直模型的BCL统一起来。大部分难以轻松移植到不同垂直模型的功能专门包含在mscorlib.dll中。

# .Net版本

此部分参考资料为:

从上面的简单了解中我们知道有 .Net Framework,.Net Core,.Net Standard,Xamarian,那么它们之间都有什么区别呢?先来看下它们的总体情况:

GitTheory

.Net名称 OS 开源 用途
.NET Framework Windows 不开源 用于生成在 IIS 上运行的 Windows 桌面应用程序和 ASP.NET Web 应用程序。
.NET Core Windows、Linux、macOS 开源 用于生成跨平台的控制台应用程序、ASP.NET Core Web 应用程序和云服务。
Xamarin iOS、Android、macOS 开源 用于生成适用于 iOS 和 Android 的移动应用,以及适用于 macOS 的桌面应用程序。
.NET Standard 开源 用于生成可以从所有 .NET 实现(如 .NET Framework、.NET Core 和 Xamarin)引用的库。

.Net Core 和 .Net Standard之间的关系:

  • .Net Core:
    • 是最新的.Net实现,它不仅开放源代码,而且还适用于多个OS。
    • .Net Core CLI能够用于开发的所有方面,包括创建,生成,测试和打包项目。.Net Core的另一个巨大优势是它支持独立部署,可以使用Docker对应用程序进行容器化处理,这样同一台计算机可以运行不同版本的 .Net Core,它们互不干扰。
  • .Net Standard:
    • 是所有.Net实现都必须实现的一组基本API,被称为基类库(BCL),它包括基元类型、文件 I/O、网络、反射、序列化、XML 等。通过targeting .Net Standard,可以生成跨所有.Net应用程序共享的库,无论它们是哪个.NET实现或OS上运行。
    • .Net Standard是一种规范,每个 .Net Standard 版本都定义了一组API,为了与相应版本保持一致,所有的 .Net 实现都必须提供这些API。可以将 .Net Standard看作是另一个 .Net 实现,不同的是它无法生成应用程序,只能生成库。
    • 有一种兼容模式。如果安装的 NuGet 包没有为目标框架提供库,也没有为 .NET Standard 提供库,那么 NuGet 会转而求助于 .NET Framework。也就是说,可以引用 .NET Framework 库,就像是定目标到 .NET Standard 一样。
  • 可以把它们想象成是HTML和浏览器,将HTML规范看作是 .Net Standard,将不同的浏览器看作是 .Net 实现,如 .NET Framework、.NET Core 和 Xamarin。
  • .Net Standard是用于所有Windows垂直模型的一个类库,.Net Core就是这样一个垂直模型,它是完整的,功能丰富的.Net Framework的一个分支,并且是开源和跨平台的。

要查看 .Net Standard对每个 .Net实现的支持,请看.NET Standard Versions (opens new window)

# .Net开发

# 编译过程

为了执行C#代码,必须把它们转换为目标操作系统能理解的语言,即本机代码(native code),这个过程称为编译,它包含两个阶段:

  1. 将代码编译为中间语言(Common Intermediate Language,CIL)代码,以前被称为Microsoft Intermediate Language(MSIL)。这些代码并非专门用于任何一种操作系统,也非专门用于C#,其他 .Net 语言比如(Visual Basic .Net 或F#)也会编译为这种语言。
  2. 有两种方式将CIL代码编译为本机代码:
    1. 使用Just-In-Time(JIT)编译器,将上一步的CIL编译成专用于OS和目标机器架构的本机代码。JIT名称反映了CIL代码仅在需要时才编译,可以在应用程序的运行过程中动态发生。这种情况意味着将C#代码部署到一个平台上,代码会保持CIL形式,直到请求调用方法时才编译。
    2. 使用Ahead-of-Time(AOT)编译器,这种是预先编译,可以理解为跟C++一样,在程序集被部署前,先编译为目标平台的本机代码,AOT编译中使用的工具是NGEN。

# 程序集

在编译应用程序时,所创建的CIL代码存储在一个程序集(assembly)中,程序集包括可执行的应用程序文件和其他应用程序使用的库(dll等)。

程序集可以看成是一个或多个模块的逻辑性分组,是重用,安全性和版本控制的最小单元,它是自解释的,它记录了它需要访问的其他程序集。

在VS开发环境中,一个解决方案可包含多个项目,而每个项目就是一个程序集,应用程序包含:应用程序域(AppDomain),程序集(Assembly),模块(Module),类型(Type),成员(MemberInfo),它包括EventInfo,FieldInfo,MethodInfo,PropertyInfo。

它们之间应该是从属关系,一个AppDomain能包括N个Assembly,一个Assembly包括N个Module,一个Module包括N个Type,一个Type包括N个成员,它们都在System.Reflection命名空间下。

公共语言运行库CLR加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局

一个程序运行起来,有一个应用程序域(AppDomain),这个应用程序域中放了我们用到的程序集(Assembly),我们所写的代码会编译到程序集文件中,在运行时以Assembly对象方式加载到内存中运行,每个类以Type对象方式加载到内存。

# 托管代码

在将代码编译为CIL,再用JIT编译器将它编译为本机代码后,CLR的任务尚未全部完成,需要管理正在执行的代码,这个阶段称为运行时(runtime),CLR管理内存,处理安全性以及允许跨语言调试。

不受CLR控制的应用程序属于非托管类型,比如C++编写的此类应用程序,访问操作系统底层功能的应用程序,但是在C#中,只能编写在托管环境中运行的代码,将使用CLR的托管功能,让.NET处理与操作系统的任何交互。

# 垃圾回收

托管代码的一个重要功能是垃圾回收(garbage collection),它可确保应用程序不再使用某些内存时,完全释放这些内存,注意它是在不可预知的时间里执行这项操作,需要许多内存的应用应该自行完成清理工作而不是坐等垃圾回收。

# 打包类库

  1. Visual Studio中创建Class Library(.Net Standard)项目,在项目属性Build子选项卡中选中Generate XML documentation file,然后使用Release选项来编译成DLL。
  2. 打开Developer Command Prompt For VS 2019命令行:
    1. cd到类库项目路径下
    2. msbuild Project.csproj /t:pack /p:Configuration=Release
    3. 得到NuGet包,将该包复制到C:\Program Files (x86)\Microsoft SDKs\NuGetPackages目录下。
  3. 在Visual Studio中创建其他项目,然后打开Tools | NuGet Package Manager | Package Manager Console,使用Install-Package PackageName 来安装。

# 从.Net Framework迁移

  1. 识别第三方依赖,解决它们的跨平台。
  2. 列出目前在程序中使用但是并未被.Net Core框架支持的API。可以使用这个工具doenet-apiport (opens new window)

# 总结

创建.NET应用程序所需的步骤:

  1. 使用某种 .NET语言编写应用程序代码。
  2. 把代码编译为CIL。
  3. 使用JIT将CIL编译为本机代码。
  4. 在CLR/CoreCLR托管本机代码。

第二步编译为CIL的C#代码未必包含在一个单独的文件中,可以把应用程序放在多个源代码文件中,再将其编译到一个单独的程序集中,这个过程称为链接。

# CSharp相关

C#是可运行在 .Net CLR/CoreCLR 上的应用程序之一,它从C和C++语言演化而来,是专为 .Net平台创建的。C#比C++语法要简单,在C++中能完成的任务几乎都能利用C#完成,C#中的与C++高级等价的功能(如直接访问和处理内存),只能在标记为"unsafe"的代码中使用。C#代码比C++更容易写的健壮,它能使用.Net Framework代码库提供的每种功能,但并非所有的功能都已移植到 .Net Core。

# C#能做的应用

  • 桌面应用程序。这些应用有我们很熟悉的Windows外观和操作方式,使用 .Net Framework的Windows Presentation Foundation(WPF)模块可以简单地生成应用程序,WPF是一个控件库,其中的控件可用于建立Windows用户界面(UI)。
  • Windows Store应用程序。针对触摸设备设计,通常全屏运行,重点在于简介清晰。
  • 云/Web应用程序。 .Net Framework和 .Net Core包括一个动态生成Web内容的强大系统- ASP.NET。
  • WebAPI。 建立REST风格的HTTP服务的理想框架,支持客户端,包括移动设备和浏览器。
  • WCF服务。灵活创建各种分布式应用程序的方式。使用WCF可以通过局域网或Internet交换各种数据,无论使用什么语言创建WCF服务,无论WCF驻留在什么系统上,都使用一样简单的语法。

这些应用访问数据库时,可以通过.NET Framework的Active Data Objects .Net(ADO.NET)部分,ADO.NET Entity Framework或C#的LINQ(Language Integrated Query)来实现。对于需要数据库访问的 .Net Core应用程序,将使用Entity Framework Core库。