C# 版本史:从 1.0 到 14,语言特性如何演进
梳理 C# 自 2002 年以来的版本脉络——从传统 OO 到泛型、LINQ、async/await、模式匹配、record 与 Span,再到 C# 14 的 extension members 与 C# 15 预览。
如果你写过一段时间 C#,很可能经历过这样的困惑:
这段
record语法是哪年加的?async/await之前大家怎么写异步?为什么 Unity 项目里用不了最新的语言特性?
这些问题指向同一件事:C# 不是一成不变的「微软版 Java」,而是一套持续演进的语言。 从 2002 年的 1.0 到 2025 年的 14,几乎每一版都在回答同一个问题——怎样让程序员写得更少、更安全、更快。
我不打算把它写成逐条罗列的 changelog。C# 二十多年有一条很清晰的主线:从 Java 风格的传统 OO 语言出发,逐步加入泛型、函数式编程、LINQ、异步、模式匹配、值语义、Span<T> 等高性能内存编程能力,正在变成一门兼顾高级抽象与底层性能的现代通用语言。
本文专注 语言特性 的演进脉络。若你想了解 .NET 为何一度锁在 Windows、开源为何来得偏晚,可以读 .NET 的平台弯路;若关心 Unity 里 Mono、IL2CPP 与 CoreCLR 的关系,见 Unity 的 C# 运行时。
资料范围
本文资料整理截至 2026 年 9 月 21 日。
- 最新正式版:C# 14,2025 年 11 月随 .NET 10 发布。1
- 最新预览版:C# 15 Preview,随 .NET 11 Preview 开发,计划 2026 年 11 月正式发布;已公开 Union Types、Closed Hierarchies、内存安全模型重构等特性。2
版本特性与发布时间以 Microsoft Learn 官方版本史 为准。3
版本历史总览
下表按发布时间排列。第三列「配套运行时」是 默认绑定 关系;早期 C# 也可在较新的 Framework 上编译,但新特性往往依赖对应 CLR(运行时引擎)与 BCL(Base Class Library,基础类库,即 System.* 等标准 API)。45
| 版本 | 时间 | 配套运行时 | 最有代表性的变化 |
|---|---|---|---|
| C# 1.0 | 2002-01 | .NET Framework 1.0 | 类、接口、结构体、属性、委托、事件、特性、异常、GC;外观像 Java,但已有 struct / ref / out / unsafe 等差异化设计 |
| C# 1.2 | 2003-04 | .NET Framework 1.1 | 小幅修正;foreach 在 IEnumerator 实现 IDisposable 时自动调用 Dispose |
| C# 2.0 | 2005-11 | .NET Framework 2.0 | 泛型、Nullable<T>、迭代器(yield)、匿名方法、分部类;CLR 级 reified generics(具化泛型),告别 ArrayList + 强转 |
| C# 3.0 | 2007-11 | .NET Framework 3.5 | LINQ、Lambda、扩展方法、表达式树(expression trees)、var、匿名类型;C# 从纯 OO 转向 OO + 函数式 混合范式,ORM/动态查询的基础设施 |
| C# 4.0 | 2010-04 | .NET Framework 4.0 | dynamic、命名/可选参数、泛型协变/逆变;主要服务 COM 互操作与动态场景 |
| C# 5.0 | 2012-08 | .NET Framework 4.5 | async / await;编译器生成状态机,异步从 callback / BeginXXX 变成近似同步的写法 |
| C# 6.0 | 2015-07 | .NET Framework 4.6 | 字符串插值、?. 空传播、nameof、表达式体成员;Roslyn 编译器开源,编译器即服务 |
| C# 7.0 | 2017-03 | .NET Framework 4.7 / .NET Core 1.x | 元组、模式匹配、局部函数、ref return、discard(_) |
| C# 7.1 | 2017-08 | .NET Core 2.0 | async Main、default literal、元组元素名推断;首次引入小版本发布与 LangVersion 配置 |
| C# 7.2 | 2017-11 | VS 2017 15.5+ | ref struct、readonly struct、in / ref readonly;Span<T> 时代的基础设施,栈分配与零拷贝切片 |
| C# 7.3 | 2018-05 | .NET Core 2.1 / .NET Framework 4.8 | stackalloc / fixed / 泛型约束性能增强;元组 ==、属性 backing field 特性 |
| C# 8.0 | 2019-09 | .NET Core 3.0 | 可空引用类型(nullable reference types)、switch 表达式、异步流、索引/范围、默认接口实现;现代 C# 基本成型 |
| C# 9.0 | 2020-11 | .NET 5 | record、init、顶层语句、关系/逻辑模式、nint、函数指针;数据建模与算法分离 |
| C# 10 | 2021-11 | .NET 6 | record struct、global using、文件范围命名空间、插值字符串处理器;年度发布节奏确立 |
| C# 11 | 2022-11 | .NET 7 | 泛型数学(generic math)、static abstract 接口成员、原始字符串字面量、required、列表模式、ref 字段 |
| C# 12 | 2023-11 | .NET 8 | 主构造函数、集合表达式、内联数组(inline arrays) |
| C# 13 | 2024-11 | .NET 9 | params 集合、新 System.Threading.Lock 语义、ref struct 可实现接口/作泛型参数、分部属性 |
| C# 14 | 2025-11 | .NET 10 | 扩展成员(extension members)、field 关键字、空条件赋值、Span 隐式转换增强;当前最新稳定版 |
| C# 15 Preview | 2026(预览) | .NET 11 Preview | Union Types、Closed Hierarchies、内存安全模型重构、扩展索引器;计划 2026-11 正式发布,特性仍可能变动 |
语言版本 ≠ 你能用的特性
编译器认某段语法,不代表目标运行时和库一定支持。C# 8 的可空引用类型、C# 9 的 record、C# 11 的泛型数学,都依赖对应的 BCL 与 CLR 能力。Unity 等使用旧 Mono 分支的环境,往往卡在 C# 9 甚至更低——这是 运行时 的限制,不是语法本身的问题。
演化主线
核心论点可以概括为:
C# 的二十多年,并不是不断堆砌语法糖,而是在不断消除「高级抽象」和「底层性能」之间的边界。
C# 1.0:一门现代化的 OO 语言
C# 1.0 于 2002 年 正式发布,目标是做一门简单、现代、类型安全、面向对象的通用语言。3
当年的写法看起来确实很像 Java:
class Player
{
public string Name { get; set; }
public void Move() { }
}但 C# 从一开始就加入了 Java 当时没有、或设计方式明显不同的东西:struct、属性、委托/事件、运算符重载、特性、ref/out、unsafe。
尤其是 属性、委托/事件、struct、ref/out,后来一直成为 C# 很有辨识度的语言特性。微软官方也把 C# 1.0 描述为相较现代 C# 相当冗长的语言——当时没有泛型、LINQ、Lambda、async/await、var、模式匹配、可空引用类型。3
第一场革命:泛型与 LINQ
C# 2.0:泛型真正改变了类型系统
2005 年 C# 2.0 是第一个巨大飞跃。此前:
ArrayList list = new ArrayList();
list.Add(123);
int value = (int)list[0]; // 运行时才能发现类型错误C# 2:
List<int> list = new();
list.Add(123);
int value = list[0]; // 编译期类型安全这不仅是语法糖,而是 CLR 本身支持的 reified generics(具化泛型)——与 Java 的 type erasure(类型擦除)形成鲜明对比。此外还有:
Nullable<T>:值类型可表达「没有值」(int?等价于Nullable<int>)yield迭代器:用yield return懒生成序列,编译器帮你实现IEnumerable<T>- 分部类(partial class):同一个类拆到多个文件编译,常见于 WinForms / 源生成器代码
- getter/setter 独立访问控制:
public int X { get; private set; }
IEnumerable<int> Range()
{
yield return 1;
yield return 2;
}C# 3.0:可能是历史上最重要的一版
2007 年 C# 3.0 值得单独用一大章。今天我们认为「理所当然」的 C#,很大一部分都是 C# 3 带来的:
Lambda
LINQ
扩展方法
表达式树
var
匿名类型
对象/集合初始化器
自动属性var adults = users
.Where(x => x.Age >= 18)
.OrderBy(x => x.Name)
.Select(x => x.Name);背后实际上是多项语言特性一起工作:
Lambda → 扩展方法 → 泛型 → 类型推断 → LINQ更厉害的是,Lambda 不一定编译成委托,也可以编译成 表达式树:
Expression<Func<User, bool>> expr = user => user.Age >= 18;这成为 Entity Framework、LINQ to SQL、ORM 动态查询生成的基础。微软官方直接把 C# 3.0 称为一次重大变化,认为它开始让 C# 成为 OO + 函数式 的混合语言。3
第二场革命:动态与异步
C# 4.0:dynamic
2010 年 C# 4.0 还加入了命名/可选参数、泛型协变/逆变,但最值得单独说的是 dynamic。
普通 C# 变量在编译期就绑定了类型——你写 value.Foo(),编译器会检查 value 的类型上有没有 Foo 这个方法,没有就直接报错。dynamic 把这一步推迟到 运行时:编译器只确认「这是个动态值」,成员解析交给 DLR(Dynamic Language Runtime) 在运行期根据对象的实际类型来决定。6
dynamic value = GetSomething();
value.Foo(); // 编译通过;运行时再找 Foo
Foo(name: "Alice", age: 20); // 命名参数如果运行时对象上 根本没有 Foo,不会变成编译错误,而是抛出 RuntimeBinderException:
dynamic value = "hello";
value.Foo(); // 编译 OK
// 运行时报错:'string' does not contain a definition for 'Foo'参数个数或类型对不上,同样在运行期才暴露。这和 JavaScript、Python 等动态语言的体验类似——灵活,但失去了 C# 静态类型检查的主要安全感。因此 dynamic 主要用在 COM 互操作(Office、旧式 Windows API)、与 Python/IronPython 等动态语言交互、或 JSON 反序列化后临时操作等「编译期实在无法确定类型」的场景。日常业务代码里很少大面积使用。
C# 4.0 同版的其他特性
命名参数与可选参数 让你调用方法时可以按名字传参、省略有默认值的参数,减少大量重载:
void Log(string message, int level = 1) { }
Log("ok"); // 可选参数:level 取默认值 1
Log(message: "warn", level: 2); // 命名参数:不必按声明顺序泛型协变与逆变(variance)解决的是:泛型类型之间能不能像普通继承那样赋值。C# 2 的泛型默认是 不变(invariant)的——List<string> 不能赋给 List<object>,哪怕 string 是 object 的子类。
C# 4 在 接口和委托 上引入 out / in 修饰类型参数:
- 协变(covariance,
out T):T只作为输出(返回值等),则子类型的泛型可以赋给父类型的泛型 - 逆变(contravariance,
in T):T只作为输入(参数等),则父类型的泛型可以赋给子类型的泛型
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings; // OK:IEnumerable<out T> 协变
Action<object> actObj = o => Console.WriteLine(o);
Action<string> actStr = actObj; // OK:Action<in T> 逆变直觉上:协变像「只读容器可以放宽类型」,逆变像「只写回调可以收窄类型」。类(如 List<T>)本身仍是不变的——这是有意设计,避免运行期类型安全问题。
C# 5.0:async / await
2012 年 C# 5 的主题几乎只有一个。此前异步代码充满 callback、BeginXXX / EndXXX、continuation;现在可以写成近似同步代码,编译器自动生成状态机:
async Task<string> DownloadAsync()
{
return await httpClient.GetStringAsync(url);
}微软官方明确称 async / await 是 C# 5 的真正主角。3 后来 JavaScript、Python、Rust、Swift 等语言都形成了类似的 async 模型。
第三阶段:Roslyn 与「让代码变少」
C# 6:语言开始明显追求开发体验
2015 年 C# 6 单独看没有 LINQ 或 async 那样的「核弹级」功能,但形成了后来非常明确的设计方向:减少样板代码。
$"Hello {name}" // 字符串插值
player?.Weapon?.Fire() // 空传播
nameof(Player) // 编译期安全的名称
public int Damage => Attack * 2; // 表达式体成员还有一个历史意义重大的事件:Roslyn——C# 编译器被重写为 C# 编写并开源,编译器本身也成为 API(语法树、语义模型、分析器、源生成器等)。3
第四阶段:模式匹配与高性能 C#
C# 7:模式匹配与 ref 语义
2017 年 C# 7 引入模式匹配与元组解构:
if (obj is Player player) { /* ... */ }
(string name, int age) GetUser() => ("Alice", 20);还有局部函数、discard _、二进制字面量、throw 表达式、ref 局部变量 / ref 返回——C# 开始认真解决「高级语言抽象与底层性能之间的矛盾」:
ref Vector3 GetPosition() => ref position;C# 7.2 / 7.3:Span 时代的基础设施
这一阶段非常值得游戏开发者关注。出现 readonly struct、ref struct、in、ref readonly、stackalloc 改进:
Span<int> values = stackalloc int[128];开始允许栈分配、零拷贝切片、避免 GC、ref 语义,同时保留类型安全——为 Span<T>、Memory<T>、System.IO.Pipelines、高性能网络、游戏引擎、序列化铺路。
C# 8:现代 C# 基本成型
2019 年 C# 8 又是一个超级大版本,也是第一个主要面向 .NET Core 的大版本。
可空引用类型
string? name = GetName();
Console.WriteLine(name.Length); // 编译器警告:Possible null reference这不是 Nullable<T>,而是编译器进行静态空流分析,系统性对付 NullReferenceException。
switch 表达式与模式匹配
// 以前
switch (state)
{
case State.Idle: return 0;
case State.Run: return 1;
default: return -1;
}
// C# 8
return state switch
{
State.Idle => 0,
State.Run => 1,
_ => -1
};此外还有异步流(IAsyncEnumerable<T>)、索引/范围(array[^1]、array[1..5])、using 声明、默认接口实现、??=。3
C# 9:数据建模
2020 年 C# 9 引入 record——自动获得值相等、ToString、解构、with:
public record Player(string Name, int Health);
var player2 = player1 with { Health = 50 };init 仅初始化 setter 表示属性只能在对象构造阶段赋值,之后只读;配合 with 做非破坏性复制(改一个字段、其余照抄)。还有顶层语句、关系/逻辑模式(value is > 0 and < 100)、nint/nuint、函数指针等,让 C# 终于拥有简洁的不可变数据建模能力。3
C# 10–12:年度节奏下的现代化
C# 10(2021) 继续删除仪式性代码:文件范围命名空间(namespace Ethertia;)、global using、record struct,以及容易被忽视但对性能很重要的 插值字符串处理器——表面语法更高级,生成代码反而可以更高效。
C# 11(2022) 的 泛型数学 通过 static abstract 接口成员解决 T + T 不能写的问题:
static T Add<T>(T a, T b) where T : INumber<T> => a + b;还有原始字符串字面量(""" 多行字符串)、required 成员、列表模式、file 局部类型、ref 字段、scoped ref。
C# 12(2023) 把主构造函数扩展到任意 class/struct,并引入集合表达式:
// 以前
class Player
{
private readonly string name;
public Player(string name) => this.name = name;
}
// C# 12
class Player(string name) { }
int[] values = [1, 2, 3];
int[] all = [..a, ..b]; // spread 展开C# 13–14:拆掉限制、扩展成员
C# 13(2024) 的 params 不再局限于数组,可用于 Span<T> 等集合类型;新的 System.Threading.Lock 让 lock 语句生成基于作用域的逻辑;ref struct 可实现接口、可作为泛型参数——C# 团队在不断拆掉 GC / ref struct / 泛型之间过去留下的限制。
C# 14(2025) 是当前最新稳定版,重点是 扩展成员(extension members)——从扩展方法进化到可扩展属性、运算符等:
// C# 3:只能扩展方法
public static int Foo(this Player player) => player.Health;
// C# 14:extension members(示意)
extension(Player player)
{
public int HealthPercentage
=> player.Health * 100 / player.MaxHealth;
}field 关键字简化属性后备字段访问:
public int Health
{
get;
set => field = Math.Max(value, 0);
}还有空条件赋值(player?.Health = 100)、partial 事件/构造函数、Span 隐式转换增强。17
C# 15 Preview:向代数数据类型靠近
预览特性,可能变动
以下 C# 15 内容均处于 Preview,计划随 .NET 11 于 2026 年 11 月正式发布,语法与语义仍可能在后续 preview 中调整。生产项目请勿依赖。2
Union Types(联合类型)
public union Pet(Cat, Dog, Bird);
Pet pet = new Dog("Rex");
var name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
// 无需 _ 默认分支——编译器保证 exhaustive
};Union 声明值恰好是固定 case 类型之一,彼此不必有继承关系,非常接近 Rust 的 enum 或 TypeScript 联合类型的思想。8
Closed Hierarchies(封闭继承层次)
public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;
// switch 覆盖所有直接子类型即可,无需 _
var label = state switch
{
Closed => "closed",
Open o => $"open {o.Percent}%"
};closed 修饰的类隐式 abstract,仅允许在同一程序集内派生,编译器因此能做穷尽性检查。9
内存安全模型重构
C# 15 开始重新思考 unsafe 的含义:过去「出现 pointer 即 unsafe」;新设计逐渐变成「真正访问无法被编译器验证的内存,才属于 unsafe 操作」。指针类型本身未必 unsafe,*p、p->field、p[index] 等解引用才需要 unsafe 上下文——更接近 Rust「哪些操作破坏了编译器能证明的安全边界」的哲学。10
附:几个文中点到、值得一句话的概念
| 概念 | 一句话 |
|---|---|
| reified generics | 泛型类型信息在运行时保留,List<int> 和 List<string> 是两种不同的类型 |
| 表达式树 | Lambda 不编译成 IL,而是编译成可遍历、可翻译的 AST,供 ORM 等转成 SQL |
| 协变 / 逆变 | 见上文 C# 4.0;out T 协变、in T 逆变,仅适用于接口与委托 |
ref struct | 必须在栈上分配、不能装箱、不能进堆;Span<T> 的载体,服务零分配场景 |
init | 属性只能在构造函数或对象初始化器里赋值,之后不可改 |
with | record 的非破坏性复制:copy with { Field = newValue } |
| 主构造函数 | 构造参数直接写在类型声明上,编译器生成字段与构造函数体 |
| 集合表达式 | [1, 2, ..other] 统一初始化数组、List、 Span 等, .. 为 spread |
横切主题:三条线在版本间接力
模式匹配
| 版本 | 里程碑 |
|---|---|
| C# 7 | is 模式、switch 模式、out 变量 |
| C# 8 | switch 表达式、属性/元组/位置模式 |
| C# 9 | 关系模式、and/or/not、is not null |
| C# 11 | 列表模式 |
| C# 15 Preview | union 模式、closed hierarchy 穷尽 switch |
值类型与性能
| 版本 | 里程碑 |
|---|---|
| C# 7.2 | ref struct、in / ref readonly |
| C# 8 | stackalloc、Index/Range |
| C# 9 | nint、function pointers |
| C# 11 | ref fields、scoped ref |
| C# 12 | 内联数组 |
| C# 13 | ref struct 泛型约束、params Span<T> |
| C# 14 | Span 更多隐式转换 |
数据类与少写样板
| 版本 | 里程碑 |
|---|---|
| C# 3 | 自动属性、对象/集合初始化器 |
| C# 6 | 表达式体成员、字符串插值 |
| C# 9 | record、init、with |
| C# 10 | record struct |
| C# 12 | 主构造函数、集合表达式 |
| C# 14 | field 关键字、partial 构造函数 |
实用:如何指定语言版本
默认情况下,语言版本由目标框架(TFM)决定。4
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<!-- 默认即 C# 14 -->
</PropertyGroup>需要显式指定时,使用 LangVersion:
<LangVersion>13.0</LangVersion> <!-- 锁定 C# 13 -->
<LangVersion>latest</LangVersion> <!-- 已安装 SDK 的最新版 -->
<LangVersion>preview</LangVersion> <!-- 含 C# 15 等预览特性 -->| 目标框架 | 默认 C# 版本 |
|---|---|
| .NET 11.x(预览) | C# 15 |
| .NET 10.x | C# 14 |
| .NET 9.x | C# 13 |
| .NET 8.x | C# 12 |
| .NET 6.x | C# 10 |
| .NET Framework(全部) | C# 7.3 |
写给 Unity 开发者
Unity 的 C# 语言版本上限,取决于 Editor/Player 使用的脚本后端与 Roslyn 版本,而不是你本机装的最新 .NET SDK。Unity 6 及更早版本通常卡在 C# 9 左右;Unity 7 迁移 CoreCLR 后,才有机会跟上 C# 14 与现代 BCL。详见 Unity 的 C# 运行时。
收束
若把 C# 的演进压缩成一条叙事线:
C# 1 → 现代 OO(属性 / 委托 / struct)
C# 2 → 类型系统革命(泛型 / nullable / 迭代器)
C# 3 → 函数式 C#(LINQ / Lambda / 表达式树)
C# 5 → 异步革命(async / await)
C# 6 → Roslyn 与语法现代化
C# 7 → 高性能 C#(ref / ref struct / Span 基础)
C# 8 → 可空引用 + 模式匹配成型
C# 9 → record / 数据导向语法
C# 11 → 泛型数学
C# 12 → 集合表达式 / 主构造函数
C# 13 → ref struct 解限
C# 14 → 扩展成员
C# 15 → Union / closed hierarchy / 内存安全(预览)理解这条线,比记住每个版本的完整特性列表更有用。若你关心「语言设计激进,为何生态仍被 Java 压着」——那是平台战略的故事,见 .NET 的平台弯路。
未纳入正式版的特性状态可在 dotnet/roslyn 与 dotnet/csharplang 仓库中跟踪。11
注释
-
Microsoft Learn,What's new in C# 14。C# 14 为当前最新正式版,需 .NET 10。 ↩ ↩2
-
Microsoft Learn,What's new in C# 15。C# 15 预览特性列表与 .NET 11 配套关系。 ↩ ↩2
-
Microsoft Learn,The history of C#。各版本特性列表、发布时间与官方叙事。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn,C# language versioning。语言版本与目标框架的默认对应关系及
LangVersion配置。 ↩ ↩2 -
Microsoft Learn,Base Class Library。BCL 是随 .NET 发布的标准类库,与 CLR 并列。 ↩
-
Microsoft Learn,dynamic(C# reference)。
dynamic的运行时分派机制与RuntimeBinderException行为说明。 ↩ -
.NET Blog,Introducing C# 14。extension members 等 headline 特性的官方介绍。 ↩
-
.NET Blog,Explore union types in C# 15。Union Types 的设计动机与 exhaustive matching 语义。 ↩
-
.NET Blog,Explore new features available in C# 15 preview。Closed Hierarchies 与 Union Types 的关系说明。 ↩
-
.NET 11 Preview 5 Release Notes,C# updates。Memory Safety / unsafe 模型演进(预览阶段)。 ↩
-
GitHub,dotnet/roslyn。Roslyn 编译器仓库,含语言特性实现状态与预览功能跟踪。 ↩