C#语言简介

C#最初是微软仿照Java设计的纯面向对象应用程序开发语言,在语法、生态等各个方面都和Java有些相似。然而由于出现晚、应用场景不多、生态圈较小、国内十分冷门等各种原因,C#没什么历史包袱,一些老旧的特性、技术都会被激进的淘汰掉,于是C#的语言特性反超了Java,反倒成了Java模仿的对象。C#语言有其独特的应用场景,也非常适合在学习Java时作为补充,通过参考对比来感受这两种现代编程语言的优势。
本系列笔记使用目前最新的.Net6平台作为运行时环境,但相关的语言特性还是从最基础的早期版本开始介绍。
微软官方文档:https://learn.microsoft.com/en-us/dotnet/csharp/
提醒:C#部分微软官方文档尽量阅读英文版,中文版应该是用较为古早的翻译器机翻的,质量奇差。
.Net技术简介和历史

C#仅仅是一门语言规范,运行C#语言程序需要先将源代码编译为IL(类似Java字节码),运行IL则需要CLR运行时的支持(类似Java的HotSpotJVM)。实际上按照微软最初的设想,.Net不仅仅支持C#语言而是一个通用的平台,因此它还支持VB.Net、F#甚至出现了IronPython,但后面几种语言实在太过小众,远不如JVM生态中Kotlin、Groovy、Scala、Clojure等百花齐放的状态,因此在很多人的印象中.Net技术基本等同于C#。
按照历史发展的顺序,可以运行C#的运行时包括微软较早开发的仅支持Windows操作系统的.Net Framework,Xamarin公司(已被微软收购)开发的跨平台运行时Mono,以及微软2016年新推出的跨平台运行时.Net Core。其中,.Net Framework最终版本停留在了4.8,微软表示后续不会再继续更新该运行时,而是全面转向了.Net Core,再后来又为了展示抛弃.Net Framework全面转向.Net Core的决心,2020年微软将.Net Core改名为了.Net并发布.Net5版本,截至2021年底发布了LTS版本的.Net6。
.Net Framework:最早的.Net运行时,GUI框架Winform、Web框架ASP.Net MVC等技术都广泛使用,最终版本停留在了4.8,并不再更新了。
.Net Core:微软推出的新.Net跨平台运行时,支持最新的工具和特性,老的.Net Framework包含的功能也基本迁移到了这个版本中,但并非100%完善。新版本改名为了.Net,这个名字和.Net技术的.Net在不同语境下是不同的含义,指代运行时的情境下其实就是新版本的.Net Core。
.Net Standard:为了统一.Net Framework、.Net Core、Mono等不同的运行时,微软提出了.Net Standard作为一个通用的标准,实现了.Net Standard标准的运行时才可以称为.Net(这里指.Net技术的.Net)运行时,面向.Net Standard标准开发的程序集能够在符合对应标准的不同运行时上运行。
.Net和Java对比
前面已经介绍过,.Net(C#)和Java(包括所谓的JavaSE和JavaEE,以及后来几乎成为事实标准的Spring)是两种比较类似而且有着许多历史纠葛的开发环境。从实际使用上来看,两者确实值得对比学习。
仅从使用框架时编码的角度来说,.Net的优势是C#先进的语法以及微软官方精心设计的框架,使用感受就是两个字“丝滑”,而Java(Spring)由于受到Java落后语法的拖累以及发展较早的缘故,虽然也在追赶但还是略逊一筹;.Net缺点则是生态不如Java成熟,.Net Core虽然是开源的,但微软官方只对自家Azure云很重视,而对于其它厂商或是开源的组件基本不予理睬,导致有一些十分细节但常用的功能只有非常烂的第三方轮子,甚至无轮子可用,让人恼火,给人一种差点就完美了而功败垂成的感觉。
从实际工程角度来说,系统都是由研发团队来编码,人员肯定是流动的,团队水平必然是参差不齐的。Java比较简单,猴子都能看懂,只要整体架构不跑偏,新手小白照葫芦画瓢写写业务逻辑也问题不大,遇到问题时靠一两个老手足以“力挽狂澜”,这也就是所谓的“项目失控风险小”,Java在这一方面做的是很好的;而C#学习成本偏高,对于团队来说心智负担大,容易写出千奇百怪的代码,再加上生态不成熟,因此风险相对于Java更高。技术选型时,“心智负担”其实非常重要,C#确实是一种复杂(复杂不等同于困难)、特性较多的语言,即使是老手一段时间不接触重新开始写也得复习一下,新手就更别提了,这也是业界Java更加流行的原因之一。
其实从流行度角度来说两者差多了,在服务端开发的领域,国内互联网公司大部分都使用Java(最近也开始流行GoLang),一些要求低延时的通信、游戏等服务端也有用C++的,其余不在意Java会在GC时STW的系统基本都在转向Java的路上;确实有一些上古时期的系统采用.Net Framework开发,但新项目敢于尝试.Net Core的比较少。此外,对于C/S客户端这块,Winform还是占据主流,但都是一些古老的系统,面向的甚至是XP系统,新项目还被Electron抢走了许多份额。
从个人角度来说,如果开发一个博客之类的系统,.Net Core是个不错的选择,开发方便、部署简单,资源占用低,即使用小小的树莓派、或是512MB内存的云服务器也能运行好几个网站、数据库,Java那个让人恼火的Spring太浪费资源了,而GoLang虽然节省资源但那简陋的语法又远不能和C#相比。
那么.Net和Java究竟学习那种好呢?其实很简单,根据需求决定。对于老式Windows桌面客户端,或者Unity游戏开发,除了C#语言没有其他选择。而如果是服务端开发,以Java为主两种同时对比学习是很合适的,学习.Net Core能够吸收很多优秀的设计,作为Java的补充。
梗知识:微软起名部
微软的一些工具、产品命名有两大特点:命名特别“混乱”,而且难写难记!
.Net、C#这些名字偏偏要加一个特殊字符,不仅给我的笔记系统造成了不小的问题(只能勉强写作dotNet和csharp),早期的搜索引擎也不能识别,据说这也是C#语言冷门的一大原因。
除此之外,版本号也是令人极度费解。例如Xbox 360、Xbox One、Xbox One X/S、Xbox Series X/S,还有.Net Framwork、.Net Core、.Net Standard、.Net,看似相关,但又不同,.Net如今竟然还有两重意义。
C#开发环境搭建
在学习C#语言语法这个阶段,其实我们使用.Net Framwork或是.Net Core区别不大,但这里要注意.Net Framework仅支持Windows操作系统,而且和Visual Studio集成开发环境紧密耦合,如果你使用Linux或是不喜欢Visual Studio那是无法使用.Net Framwork的。
不过这里我们还是以最新版本的Visual Studio 2022和.Net6为例进行介绍。
使用dotNet SDK命令行工具
前面已经介绍过了.Net Core是跨平台运行时,使用.Net Core自然也可以摆脱臃肿的Visual Studio集成开发环境使用其它轻量级的文本编辑器,甚至在Linux操作系统下进行开发。
安装dotnet SDK
首先要说的是,如果我们已经安装了Visual Studio 2022,那么可以直接在Visual Studio Installer程序中安装.Net开发的各种开发组件,此时就不必再单独安装dotnet SDK了。

如果我们不打算安装Visual Studio 2022,则可以在微软官网找到单独的dotnet SDK安装程序:https://dotnet.microsoft.com/en-us/download/visual-studio-sdks
安装结束后,我们可以使用如下命令输出dotnet SDK的版本信息,以查看安装是否成功。
dotnet --version
创建工程
dotnet命令行工具可以创建各种类型的工程模板,我们可以使用以下命令查看可用的模板。
dotnet new --list

这里我们可以尝试创建一个「控制台应用」,首先我们需要新建一个文件夹,然后在该文件夹中执行以下命令。
dotnet new console
此时工具为我们生成的目录结构如下。
工程根目录
|_bin 包含编译输出的可执行文件的文件夹(编译一次后才会出现)
|_obj 包含编译过程中的中间文件的文件夹
|_工程名.csproj 工程构建的描述文件(类似Java工程的pom.xml)
|_Program.cs 例子源码文件
实际上,dotnet命令行工具也支持类似Visual Studio的解决方案(sln),但这里我们出于简单起见,就直接创建工程(csproj)了。
运行以下命令可以直接编译构建并运行当前工程。
dotnet run
注:我们可以使用dotnet --help查看命令行工具的各种帮助信息。
使用Visual Studio 2022集成开发环境
如果使用Visual Studio 2022创建工程,我们需要选择创建「控制台应用」,这里尤其注意不要把.Net Core和.Net Framwork工程搞混了,后者创建工程需要选择「控制台应用(.Net Framework)」。

选择后,按照提示输入解决方案名字,最后选择使用.Net6,即可创建完成。

C#版本与.Net版本对照表
实际开发中,我们首先需要选定在哪一个运行时上开发,不同的运行时支持的C#语言版本也不同,在稍老的运行时上开发可能导致一些最新的语言特性无法使用,这里我们给出一个对照表格。
| C#版本 | .NET版本 | 发布日期 | 特性 |
|---|---|---|---|
| C# 1.0 | .NET Framework 1.0 | 2002-02-13 | 委托、事件 |
| C# 1.1 | .NET Framework 1.1 | 2003-04-24 | APM(异步编程模型) |
| C# 2.0 | .NET Framework 2.0 | 2005-11-07 | 泛型、匿名方法、迭代器、可空类型 |
| C# 3.0 | .NET Framework 3.0 | 2007-11-06 | 隐式类型 |
| .NET Framework 3.5 | 2007-11-19 | 对象集合初始化、自动实现属性、匿名类型、扩展方法、查询表达式、Lambda表达式、 表达式树、分部类和方法、LINQ | |
| C# 4.0 | .NET Framework 4.0 | 2010-04-12 | 动态绑定、命名和可选参数、泛型的协变和逆变、互操作性 |
| C# 5.0 | .NET Framework 4.5 | 2012-08-15 | 异步和等待(async和await)、调用方信息(Caller Information) |
| C# 6.0 | .NET Framework 4.6 | 2015-07-20 | 静态导入、C# 6 中的新增功能 |
| .NET Core 1.0 | 2016-06-27 | ||
| C# 7.0 | .NET Framework 4.6.2 | 2016-08-02 | 元组、C# 7.0 中的新增功能 |
| C# 7.1 | .NET Framework 4.7 | 2017-04-05 | |
| .NET Core 2.0 | 2016-08-14 | .NET Core 2.0 的新增功能 | |
| C# 7.2 | .NET Framework 4.7.1 | 2017-10-17 | |
| C# 7.3 | .NET Framework 4.7.2 | 2018-04-30 | |
| .NET Core 2.1 | 2018-05-30 | .NET Core 2.1 的新增功能 | |
| .NET Core 2.2 | 2018-12-04 | .NET Core 2.2 的新增功能 | |
| C# 8.0 | .NET Framework 4.8 | 2019-04-18 | C# 8.0 中的新增功能 |
| .NET Core 3.0 | 2019-09-23 | .NET Core 3.0 的新增功能 | |
| .NET Core 3.1 | 2019-12-03 | .NET Core 3.1 的新增功能 | |
| C# 9.0 | .NET 5 | 2020-09-04 | C# 9.0 中的新增功能 |
| .NET 5 | 2020-10-13 | What’s new in .NET 5 | |
| C# 10.0 | .NET 6 | 2021-11-09 | 欢迎使用 C# 10 C# 10.0 中的新增功能 |