自C# 7.0以来,C#语言在类型系统方面引入了众多新数据类型、类型构造和语言特性,以提升性能、类型安全性和开发效率。本文全面整理了从C# 7.0到C# 14.0(截至2025年4月,C# 14.0为预览版)类型系统的新增内容,包括值元组、Span<T>
、ReadOnlySpan<T>
、Memory<T>
、ReadOnlyMemory<T>
、可空引用类型、记录、本机大小整数、记录结构、内联数组,以及其他增强(如只读结构、泛型数学支持)。
版本概览
以下是C# 7.0至C# 14.0中类型系统新增或增强的主要内容:
C# 版本 | 新增/增强内容 | 发布年份 | 描述 |
7.0 |
值元组(Value Tuples) |
2017 |
轻量级数据结构,支持多值返回和解构 |
7.2 |
Span, ReadOnlySpan, 只读结构, 引用结构 |
2017 |
高性能内存操作和不可变/栈分配结构体 |
8.0 |
可空引用类型, Memory, ReadOnlyMemory |
2019 |
空值安全性和托管内存块 |
9.0 |
记录, 本机大小整数, 初始化器专用类型 |
2020 |
值语义引用类型、本机整数和不可变属性 |
10.0 |
记录结构, 全局 using 指令 |
2021 |
值类型记录和简化类型引用 |
11.0 |
必需成员, 泛型数学支持, 文件局部类型 |
2022 |
强制初始化、泛型运算和类型作用域限制 |
12.0 |
内联数组 |
2023 |
固定大小数组结构,优化性能 |
13.0 |
参数集合扩展, 引用结构接口支持, 部分属性 |
2024 |
扩展params、ref struct接口和部分属性定义 |
14.0 |
field 关键字, 隐式 span 转换, nameof 增强, lambda 参数修饰符, partial 成员扩展, 空条件赋值 |
2025 |
增强属性访问、span 使用、泛型处理、lambda 表达、partial 类型和空值处理 |
以下按版本逐一详述,每节包含特性表格、代码示例和分析。
C# 7.0:值元组
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
值元组 (Value Tuples) |
轻量级值类型,支持多值返回、命名元素和解构 |
方法返回多个值、临时数据分组 |
值类型,栈分配;.NET Framework需引用System.ValueTuple包 |
概述
值元组基于System.ValueTuple
,允许方法返回多个值,支持命名元素和解构,简化数据传递。
语法
- 声明:
(type1, type2, ...) tupleName = (value1, value2, ...);
- 命名元素:
(type1 name1, type2 name2, ...) tupleName = (value1, value2, ...);
- 解构:
var (var1, var2, ...) = tupleName;
示例代码
|
public (int id, string name) GetPerson() |
|
{ |
|
return (1, "Alice"); |
|
} |
|
|
|
var person = GetPerson(); |
|
Console.WriteLine($"ID: {person.id}, Name: {person.name}"); |
|
|
|
|
|
var (id, name) = GetPerson(); |
|
Console.WriteLine($"ID: {id}, Name: {name}"); |
适用场景
- 方法返回多个相关值。
- 临时数据分组,无需定义类或结构。
- 解构赋值,简化代码。
注意事项
- 值类型,适合轻量数据。
- .NET Framework项目需引用System.ValueTuple NuGet包。
C# 7.2:Span, ReadOnlySpan, 只读结构, 引用结构
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
Span |
表示连续内存块的引用,支持读写 |
高性能数组/内存操作 |
ref struct,栈分配,生命周期限制 |
ReadOnlySpan |
只读连续内存块引用 |
高性能只读操作 |
同上,需确保内存边界安全 |
只读结构 (readonly struct) |
不可变结构体,优化性能 |
不可变数据结构 |
所有实例字段必须只读 |
引用结构 (ref struct) |
栈分配结构体 |
高性能内存管理 |
不可boxing或作为接口实现 |
概述
Span<T>
和ReadOnlySpan<T>
是高性能值类型,表示连续内存块引用,适合数组和本机内存操作。readonly struct
确保结构体不可变,ref struct
限制为栈分配,支持Span<T>
等类型。
语法
- Span:
Span<T> span = collection.AsSpan();
- ReadOnlySpan:
ReadOnlySpan<T> readOnlySpan = collection.AsSpan();
- 只读结构:
readonly struct StructName { ... }
- 引用结构:
ref struct StructName { ... }
示例代码
|
|
|
int[] numbers = [1, 2, 3, 4, 5]; |
|
Span<int> span = numbers.AsSpan(1, 3); |
|
span[0] = 10; |
|
Console.WriteLine(string.Join(", ", span.ToArray())); |
|
|
|
ReadOnlySpan<char> text = "Hello".AsSpan(); |
|
Console.WriteLine(text.Slice(0, 2).ToString()); |
|
|
|
|
|
readonly struct Point |
|
{ |
|
public int X { get; init; } |
|
public int Y { get; init; } |
|
} |
|
Point point = new() { X = 1, Y = 2 }; |
|
Console.WriteLine($"({point.X}, {point.Y})"); |
|
|
|
|
|
ref struct Buffer |
|
{ |
|
public Span<int> Data; |
|
public Buffer(Span<int> data) => Data = data; |
|
} |
|
Buffer buffer = new(numbers.AsSpan()); |
|
buffer.Data[0] = 10; |
|
Console.WriteLine(numbers[0]); |
适用场景
- 高性能字符串解析、缓冲区处理。
- 不可变数据结构(只读结构)。
- 避免堆分配(引用结构)。
注意事项
Span<T>
和ReadOnlySpan<T>
不可用于异步方法。
ref struct
限制严格,需管理生命周期。
C# 8.0:可空引用类型, Memory, ReadOnlyMemory
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
可空引用类型 |
引用类型可标记为可空,默认非null |
增强空值安全性 |
需启用可空上下文,处理编译器警告 |
Memory |
托管内存块,支持读写 |
异步和高性能内存操作 |
适合异步场景,需管理生命周期 |
ReadOnlyMemory |
只读托管内存块 |
只读异步内存操作 |
同上 |
概述
可空引用类型通过?
后缀指定引用类型是否可为null,减少空引用异常。Memory<T>
和ReadOnlyMemory<T>
表示托管内存块,支持异步场景。
语法
- 可空引用类型:
string? nullable; string nonNullable;
- Memory:
Memory<T> memory = collection.AsMemory();
- ReadOnlyMemory:
ReadOnlyMemory<T> readOnlyMemory = collection.AsMemory();
示例代码
|
|
|
#nullable enable |
|
string nonNullable = "Hello"; |
|
string? nullable = null; |
|
if (nullable != null) |
|
{ |
|
Console.WriteLine(nullable.Length); |
|
} |
|
|
|
|
|
int[] numbers = [1, 2, 3, 4, 5]; |
|
Memory<int> memory = numbers.AsMemory(1, 3); |
|
Span<int> span = memory.Span; |
|
span[0] = 10; |
|
Console.WriteLine(string.Join(", ", memory.ToArray())); |
|
|
|
ReadOnlyMemory<char> text = "Hello".AsMemory(); |
|
Console.WriteLine(text.Slice(0, 2).Span.ToString()); |
适用场景
- 增强空值安全性(可空引用类型)。
- 异步内存操作(Memory)。
- 只读数据传递(ReadOnlyMemory)。
注意事项
- 可空引用类型需显式启用。
- Memory生命周期需管理。
C# 9.0:记录, 本机大小整数, 初始化器专用类型
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
记录 (Records) |
具有值语义的引用类型,默认不可变 |
数据建模,值相等性 |
默认不可变,可添加可变行为 |
本机大小整数 (nint, nuint) |
本机大小整数,映射IntPtr/UIntPtr |
本机代码互操作 |
平台依赖,需考虑兼容性 |
初始化器专用类型 (init-only setters) |
初始化后不可变属性 |
不可变数据模型 |
仅初始化时可赋值 |
概述
记录是具有值语义的引用类型,自动实现相等性。nint
和nuint
支持本机大小整数。init
修饰符增强属性不可变性。
语法
- 记录:
public record ClassName(type1 Property1, ...);
- 本机大小整数:
nint nativeInt; nuint nativeUInt;
- init-only:
public type Property { get; init; }
示例代码
|
|
|
public record Person(string FirstName, string LastName); |
|
var person1 = new Person("Alice", "Smith"); |
|
var person2 = new Person("Alice", "Smith"); |
|
Console.WriteLine(person1 == person2); |
|
var person3 = person1 with { LastName = "Johnson" }; |
|
Console.WriteLine(person3); |
|
|
|
|
|
nint nativeInt = 42; |
|
nuint nativeUInt = 42u; |
|
Console.WriteLine($"Native int: {nativeInt}, Native uint: {nativeUInt}"); |
|
|
|
|
|
public class Student |
|
{ |
|
public string Name { get; init; } |
|
} |
|
var student = new Student { Name = "Alice" }; |
|
Console.WriteLine(student.Name); |
适用场景
- 数据传输对象(记录)。
- 本机代码互操作(nint, nuint)。
- 不可变数据模型(init-only)。
注意事项
- 记录支持继承,需保持值语义。
- 本机大小整数平台依赖。
C# 10.0:记录结构, 全局 using 指令
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
记录结构 (Record Structs) |
值类型的记录,结合值语义和性能 |
小型数据结构 |
值类型,复制成本需考虑 |
全局 using 指令 |
全局导入命名空间 |
简化类型引用 |
需平衡代码可读性 |
概述
记录结构将记录特性扩展到值类型,结合值语义和性能。全局using
简化类型引用。
语法
- 记录结构:
public record struct StructName(type1 Property1, ...);
- 全局 using:
global using System;
示例代码
|
|
|
public record struct Point(int X, int Y); |
|
var point1 = new Point(1, 2); |
|
var point2 = new Point(1, 2); |
|
Console.WriteLine(point1 == point2); |
|
var point3 = point1 with { X = 3 }; |
|
Console.WriteLine(point3); |
|
|
|
|
|
Console.WriteLine("Hello, World!"); |
适用场景
- 值类型数据建模(记录结构)。
- 大型项目命名空间管理(全局 using)。
注意事项
- 记录结构复制成本需关注。
- 全局 using 需谨慎使用。
C# 11.0:必需成员, 泛型数学支持, 文件局部类型
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
必需成员 (required members) |
强制成员初始化 |
确保关键字段初始化 |
需配合初始化器或构造函数 |
泛型数学支持 |
静态抽象接口成员支持泛型运算 |
泛型算法库 |
需运行时支持(.NET 7+) |
文件局部类型 (file modifier) |
限制类型作用域至文件 |
隔离辅助类型 |
仅限文件作用域 |
概述
required
修饰符强制成员初始化。泛型数学支持通过接口实现数值运算。file
修饰符限制类型作用域。
语法
- 必需成员:
public required type Property { get; set; }
- 泛型数学:
interface INumber<T> { static abstract T operator +(T, T); }
- 文件局部类型:
file class ClassName { ... }
示例代码
|
|
|
public class Person |
|
{ |
|
public required string Name { get; set; } |
|
} |
|
var person = new Person { Name = "Alice" }; |
|
Console.WriteLine(person.Name); |
|
|
|
|
|
public interface INumber<T> where T : INumber<T> |
|
{ |
|
static abstract T Add(T left, T right); |
|
} |
|
public readonly struct MyNumber : INumber<MyNumber> |
|
{ |
|
public int Value { get; init; } |
|
public MyNumber(int value) => Value = value; |
|
public static MyNumber Add(MyNumber left, MyNumber right) => new(left.Value + right.Value); |
|
} |
|
MyNumber a = new(1); |
|
MyNumber b = new(2); |
|
var result = MyNumber.Add(a, b); |
|
Console.WriteLine(result.Value); |
|
|
|
|
|
file class Helper |
|
{ |
|
public static void Log(string message) => Console.WriteLine(message); |
|
} |
|
Helper.Log("Test"); |
适用场景
- API 设计(必需成员)。
- 泛型数值计算(泛型数学)。
- 代码生成(文件局部类型)。
注意事项
C# 12.0:内联数组
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
内联数组 (Inline Arrays) |
固定大小数组结构,栈分配 |
高性能固定大小数组 |
固定大小,仅限结构体内 |
概述
内联数组通过[InlineArray]
特性定义固定大小数组结构,优化性能。
语法
|
[InlineArray(length)] |
|
public struct StructName |
|
{ |
|
private elementType _element0; |
|
} |
示例代码
|
[InlineArray(10)] |
|
public struct Buffer |
|
{ |
|
private int _element0; |
|
} |
|
Buffer buffer = new(); |
|
buffer[0] = 1; |
|
buffer[9] = 10; |
|
Console.WriteLine(buffer[0]); |
适用场景
注意事项
C# 13.0:参数集合扩展, 引用结构接口支持, 部分属性
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
参数集合扩展 (params Span等) |
扩展params支持Span等 |
高性能参数传递 |
需确保Span生命周期 |
引用结构接口支持 |
允许ref struct实现接口 |
扩展ref struct能力 |
仍受ref struct限制 |
部分属性 (partial properties) |
支持partial类型部分属性 |
代码生成 |
需确保定义一致 |
概述
参数集合扩展支持Span<T>
等类型。ref struct
可实现接口。部分属性支持分文件定义。
语法
- 参数集合:
void Method(params Span<T> spans);
- 引用结构接口:
ref struct StructName : IInterface { ... }
- 部分属性:
public partial type Property { get; set; }
示例代码
|
|
|
public void Process(params Span<int> spans) |
|
{ |
|
foreach (var span in spans) |
|
Console.WriteLine(string.Join(", ", span.ToArray())); |
|
} |
|
int[] numbers = [1, 2, 3]; |
|
Process(numbers.AsSpan(0, 2), numbers.AsSpan(2, 1)); |
|
|
|
|
|
public interface IBuffer |
|
{ |
|
void Process(); |
|
} |
|
ref struct Buffer : IBuffer |
|
{ |
|
public Span<int> Data; |
|
public Buffer(Span<int> data) => Data = data; |
|
public void Process() => Data[0] = 10; |
|
} |
|
Buffer buffer = new(numbers.AsSpan()); |
|
buffer.Process(); |
|
Console.WriteLine(numbers[0]); |
|
|
|
|
|
public partial class Person |
|
{ |
|
public partial string Name { get; set; } |
|
} |
|
public partial class Person |
|
{ |
|
public partial string Name { get => _name; set => _name = value; } |
|
private string _name; |
|
} |
|
var person = new Person { Name = "Alice" }; |
|
Console.WriteLine(person.Name); |
适用场景
- 高性能参数传递(参数集合)。
- 扩展
ref struct
(接口支持)。
- 代码生成(部分属性)。
注意事项
- 参数集合需管理Span生命周期。
- 部分属性需确保一致性。
C# 14.0:field
关键字, 隐式 span 转换,nameof
增强, lambda 参数修饰符, partial 成员扩展, 空条件赋值
特性表格
类型/构造 | 描述 | 主要用途 | 注意事项 |
field 关键字 |
允许在属性访问器中直接访问 backing field |
简化属性实现 |
可能与现有字段名冲突,需使用 @field 或 this.field 区分 |
隐式 span 转换 |
支持 Span<T> 、ReadOnlySpan<T> 与数组间的隐式转换 |
更自然地使用 span 类型 |
需注意 span 的生命周期 |
nameof 支持未绑定泛型 |
允许 nameof 使用未绑定泛型类型,如 nameof(List<>) |
泛型编程中的类型名称获取 |
- |
lambda 参数修饰符 |
允许 lambda 参数使用 ref 、out 等修饰符,无需指定类型 |
增强 lambda 表达式的灵活性 |
params 仍需指定类型 |
partial 构造函数和事件 |
扩展 partial 成员到实例构造函数和事件 |
分离定义和实现,适合代码生成 |
需确保 defining 和 implementing 声明一致 |
空条件赋值 |
允许在赋值左侧使用 ?. 和 ?[] ,仅在左侧非 null 时赋值 |
简化 null 检查 |
不支持 ++ 和 -- |
概述
C# 14.0(预计2025年随.NET 10发布,截至2025年4月为预览版)引入了一系列语言特性,旨在提高开发效率和代码可读性,包括 field
关键字、隐式 span 转换、nameof
增强、lambda 参数修饰符、partial 成员扩展和空条件赋值。虽然未引入全新数据类型,但这些特性显著增强了现有类型的用法。
field
关键字
概述
field
关键字允许在属性访问器中直接访问编译器生成的 backing field,无需显式声明。
示例代码
|
public class Person |
|
{ |
|
public string Name |
|
{ |
|
get => field; |
|
set => field = value?.Trim(); |
|
} |
|
} |
|
var person = new Person { Name = " Alice " }; |
|
Console.WriteLine(person.Name); |
适用场景
- 简化属性实现,特别是需要对 setter 进行处理时。
注意事项
- 如果类中已有名为
field
的字段,需使用 @field
或 this.field
区分。
- 作为C# 13.0的预览特性,C# 14.0正式支持,详见field 关键字。
隐式 span 转换
概述
C# 14.0 为 Span<T>
和 ReadOnlySpan<T>
提供了与数组的隐式转换,使其使用更加自然。
示例代码
|
Span<int> span = new int[] {1, 2, 3}; |
|
int[] array = span.ToArray(); |
|
Console.WriteLine(string.Join(", ", array)); |
适用场景
- 高性能场景中,减少显式转换。
- 与数组和 span 类型交互。
注意事项
- 需确保 span 的生命周期管理,详见Span 转换。
nameof
支持未绑定泛型
概述
允许 nameof
操作符使用未绑定泛型类型。
示例代码
|
string listName = nameof(List<>); |
|
Console.WriteLine(listName); |
适用场景
注意事项
lambda 参数修饰符
概述
允许在 lambda 表达式中为参数添加修饰符,如 ref
、out
等,无需指定类型。
示例代码
|
var increment = (ref int x) => x++; |
|
int num = 5; |
|
increment(ref num); |
|
Console.WriteLine(num); |
适用场景
注意事项
params
仍需指定类型,详见lambda 表达式。
partial 构造函数和事件
概述
扩展 partial 成员到实例构造函数和事件,允许在 partial 类型中分离定义和实现。
示例代码
|
|
|
public partial class MyClass |
|
{ |
|
public partial MyClass(int x); |
|
public partial event EventHandler MyEvent; |
|
} |
|
|
|
|
|
public partial class MyClass |
|
{ |
|
public partial MyClass(int x) { } |
|
public partial event EventHandler MyEvent; |
|
} |
适用场景
注意事项
- 需确保 defining 和 implementing 声明一致,详见partial 成员。
空条件赋值
概述
允许在赋值语句的左侧使用 ?.
和 ?[]
,仅当左侧非 null 时执行赋值。
示例代码
|
string? text = null; |
|
text?.Length = 5; |
|
|
|
List<int>? list = null; |
|
list?[0] = 10; |
|
|
|
list = new List<int> { 0 }; |
|
list?[0] = 10; |
|
Console.WriteLine(list[0]); |
适用场景
- 简化 null 检查,避免 NullReferenceException。
注意事项
结语
C# 7.0至C# 14.0的类型系统新增内容涵盖了值元组、Span、ReadOnlySpan、Memory、ReadOnlyMemory、可空引用类型、记录、本机大小整数、记录结构、内联数组等数据类型,以及只读结构、引用结构、必需成员、泛型数学支持等增强。C# 14.0通过field
关键字、隐式 span 转换等特性进一步优化了现有类型的用法。这些特性满足了从高性能内存管理到类型安全建模的多种需求。资深C#工程师可根据场景选择类型,如使用Span优化性能,记录建模数据。由于C# 14.0尚在预览阶段,建议关注dotnet/roslyn以获取最新更新。