自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 { ... }

示例代码

// Span<T> 和 ReadOnlySpan<T>
int[] numbers = [1, 2, 3, 4, 5];
Span<int> span = numbers.AsSpan(1, 3);
span[0] = 10;
Console.WriteLine(string.Join(", ", span.ToArray())); // 10, 3, 4 ReadOnlySpan<char> text = "Hello".AsSpan();
Console.WriteLine(text.Slice(0, 2).ToString()); // He // 只读结构
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})"); // (1, 2) // 引用结构
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]); // 10

适用场景

  • 高性能字符串解析、缓冲区处理。
  • 不可变数据结构(只读结构)。
  • 避免堆分配(引用结构)。

注意事项

  • 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);
} // Memory<T> 和 ReadOnlyMemory<T>
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())); // 10, 3, 4 ReadOnlyMemory<char> text = "Hello".AsMemory();
Console.WriteLine(text.Slice(0, 2).Span.ToString()); // He

适用场景

  • 增强空值安全性(可空引用类型)。
  • 异步内存操作(Memory)。
  • 只读数据传递(ReadOnlyMemory)。

注意事项

  • 可空引用类型需显式启用。
  • Memory生命周期需管理。

C# 9.0:记录, 本机大小整数, 初始化器专用类型

特性表格

类型/构造 描述 主要用途 注意事项
记录 (Records) 具有值语义的引用类型,默认不可变 数据建模,值相等性 默认不可变,可添加可变行为
本机大小整数 (nint, nuint) 本机大小整数,映射IntPtr/UIntPtr 本机代码互操作 平台依赖,需考虑兼容性
初始化器专用类型 (init-only setters) 初始化后不可变属性 不可变数据模型 仅初始化时可赋值

概述

记录是具有值语义的引用类型,自动实现相等性。nintnuint支持本机大小整数。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); // True
var person3 = person1 with { LastName = "Johnson" };
Console.WriteLine(person3); // Person { FirstName = Alice, LastName = Johnson } // 本机大小整数
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); // Alice

适用场景

  • 数据传输对象(记录)。
  • 本机代码互操作(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); // True
var point3 = point1 with { X = 3 };
Console.WriteLine(point3); // Point { X = 3, Y = 2 } // 全局 using(假设已在文件顶部)
Console.WriteLine("Hello, World!"); // 无需显式 using System

适用场景

  • 值类型数据建模(记录结构)。
  • 大型项目命名空间管理(全局 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); // Alice // 泛型数学支持
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); // 3 // 文件局部类型
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]); // 1

适用场景

  • 高性能计算。
  • 替代不安全固定缓冲区。

注意事项

  • 固定大小,运行时不可调整。

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)); // 1, 2 和 3 // 引用结构接口支持
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]); // 10 // 部分属性
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); // Alice

适用场景

  • 高性能参数传递(参数集合)。
  • 扩展ref struct(接口支持)。
  • 代码生成(部分属性)。

注意事项

  • 参数集合需管理Span生命周期。
  • 部分属性需确保一致性。

C# 14.0:field 关键字, 隐式 span 转换, nameof 增强, lambda 参数修饰符, partial 成员扩展, 空条件赋值

特性表格

类型/构造 描述 主要用途 注意事项
field 关键字 允许在属性访问器中直接访问 backing field 简化属性实现 可能与现有字段名冲突,需使用 @fieldthis.field 区分
隐式 span 转换 支持 Span<T>ReadOnlySpan<T> 与数组间的隐式转换 更自然地使用 span 类型 需注意 span 的生命周期
nameof 支持未绑定泛型 允许 nameof 使用未绑定泛型类型,如 nameof(List<>) 泛型编程中的类型名称获取 -
lambda 参数修饰符 允许 lambda 参数使用 refout 等修饰符,无需指定类型 增强 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); // Alice

适用场景

  • 简化属性实现,特别是需要对 setter 进行处理时。

注意事项

  • 如果类中已有名为 field 的字段,需使用 @fieldthis.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)); // 1, 2, 3

适用场景

  • 高性能场景中,减少显式转换。
  • 与数组和 span 类型交互。

注意事项

  • 需确保 span 的生命周期管理,详见Span 转换。

nameof 支持未绑定泛型

概述

允许 nameof 操作符使用未绑定泛型类型。

示例代码

string listName = nameof(List<>);
Console.WriteLine(listName); // List

适用场景

  • 泛型编程中,获取类型名称。

注意事项

  • 简单但强大的增强,适合反射场景。

lambda 参数修饰符

概述

允许在 lambda 表达式中为参数添加修饰符,如 refout 等,无需指定类型。

示例代码

var increment = (ref int x) => x++;
int num = 5;
increment(ref num);
Console.WriteLine(num); // 6

适用场景

  • 需要在 lambda 中修改外部变量。

注意事项

  • params 仍需指定类型,详见lambda 表达式。

partial 构造函数和事件

概述

扩展 partial 成员到实例构造函数和事件,允许在 partial 类型中分离定义和实现。

示例代码

// File1.cs
public partial class MyClass
{
    public partial MyClass(int x);
    public partial event EventHandler MyEvent;
} // File2.cs
public partial class MyClass
{
    public partial MyClass(int x) { }
    public partial event EventHandler MyEvent;
}

适用场景

  • 代码生成场景,如 UI 设计器。

注意事项

  • 需确保 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; // 执行赋值,list[0] = 10
Console.WriteLine(list[0]); // 10

适用场景

  • 简化 null 检查,避免 NullReferenceException。

注意事项

  • 不支持 ++-- 操作,详见空条件赋值。

结语

C# 7.0至C# 14.0的类型系统新增内容涵盖了值元组、Span、ReadOnlySpan、Memory、ReadOnlyMemory、可空引用类型、记录、本机大小整数、记录结构、内联数组等数据类型,以及只读结构、引用结构、必需成员、泛型数学支持等增强。C# 14.0通过field关键字、隐式 span 转换等特性进一步优化了现有类型的用法。这些特性满足了从高性能内存管理到类型安全建模的多种需求。资深C#工程师可根据场景选择类型,如使用Span优化性能,记录建模数据。由于C# 14.0尚在预览阶段,建议关注dotnet/roslyn以获取最新更新。

C#高性能开发之类型系统:从C# 7.0 到C# 14的类型系统演进全景的更多相关文章

  1. Java Web高性能开发(三)

    今日要闻: Clarifai:可识别视频中物体 最近几年,得益于深度学习技术的发展,谷歌和Facebook等企业的研究人员在图形识别软件领域取得了重大突破.现在,一家名为Clarifai的创业公司则提 ...

  2. Java Web高性能开发(二)

    今日要闻: 性价比是个骗局: 对某个产品学上三五天个把月,然后就要花最少的钱买最多最好的东西占最大的便宜. 感谢万能的互联网,他顺利得手,顺便享受了智商上的无上满足以及居高临下的优越感--你们一千块买 ...

  3. JavaWeb高性能开发(一)

    今日要闻: 淘宝删差评产业链 在你给出"差评""中评"后不久,有人会偷偷登录你的淘宝账户,把你之前给过的评价删除或改成"好评".而这种人就是 ...

  4. Java Web 高性能开发,第 3 部分: 网站优化实战

    这个系列的前两篇,介绍了前端的优化技术,这些技术秉承了前人至高无上的智慧,我只是负责吸收和传播.然而,这些技术一般也都是某某大型网站的技术经验,我们大部分人或许只能接触到相对小规模的网站,小规模的网站 ...

  5. .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)——转载

    原文链接:https://blog.walterlv.com/post/dotnet-high-performance-reflection-suggestions.html ***** 大家都说反射 ...

  6. JavaScript高性能开发的十条建议

    JavaScript高性能开发的十条建议 文/开发部 Dimmacro 编者按:javascript开发大部分程序员都做过,写出来的代码质量也千差万别,现在浏览器内嵌的解释器虽然效率已经很高了,但在客 ...

  7. Java Web 高性能开发,前端的高性能

    Java Web 高性能开发,第 2 部分: 前端的高性能 Web 发展的速度让许多人叹为观止,层出不穷的组件.技术,只需要合理的组合.恰当的设置,就可以让 Web 程序性能不断飞跃.Web 的思想是 ...

  8. 原 .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)

    大家都说反射耗性能,但是到底有多耗性能,哪些反射方法更耗性能:这些问题却没有统一的描述. 本文将用数据说明反射各个方法和替代方法的性能差异,并提供一些反射代码的编写建议.为了解决反射的性能问题,你可以 ...

  9. CozyRSS开发记录18-番外之Atom1.0的支持

    CozyRSS开发记录18-番外之Atom1.0的支持 1.对CozyRSS.Syndication批判一番 由于我工作的主要开发语言是c++,所以会看到我的c#代码写得非常朴素,很多语法糖都没有用上 ...

  10. ASP.NET Core 开发-Entity Framework (EF) Core 1.0 Database First

    ASP.NET Core 开发-Entity Framework Core 1.0 Database First,ASP.NET Core 1.0 EF Core操作数据库. Entity Frame ...

随机推荐

  1. Oracle用户的创建和授权

    1 --创建用户.密码 2 create user infouser identified by "User@2022!"; 3 --授权连接数据库权限 4 grant conne ...

  2. 第15章 流与IO

    第15章 流与IO 15.1 .NET 流的架构 .NET 流的架构主要包含三个概念:** 后台存储 . 装饰器 以及 流适配器 **,如图所示: C7.0 核心技术指南 第7版.pdf - p655 ...

  3. 数字先锋 | 车企,出海!天翼云AOne擦亮车企“智慧服务”新名片!

    近年来,中国汽车市场迎来巨变,消费者的消费习惯不断变迁,价格战愈演愈烈......如何紧跟数字化转型步伐,实现稳健经营,成为车企所面临的时代命题. 作为一家科技型制造企业,某车企主营业务涉及汽车及核心 ...

  4. 如何利用cursor+deepseek来最大程度减少组件库的学习成本!

    在当今的软件开发领域,开发者们面临着不断提升开发效率与降低上手成本的挑战.本文档的核心目的,便是助力开发者们实现这一目标,特别是通过巧妙运用组件官网文档,并结合 Cursor 与 DeepSeek 等 ...

  5. 阿里的DataV和QuickBi区别

    首先说下DataV吧 分为老版和新版(二者之间没有什么太大的差别,存在的基本都是组件上的配置或是更多不同组件的新增,但是如果你是在项目上进行开发,你首先要知道客户用的DataV用的是什么版本,如果你们 ...

  6. 发那科焊接机器人M-10iA维修总结

    发那科作为工业机器人制造商,其焊接机器人产品广泛应用于各种工业领域.然而,随着时间的推移,焊接机器人可能会出现故障,因此了解发那科焊接机器人M-10iA维修知识显得尤为重要. 一.日常法那科机械手维护 ...

  7. 普通人如何靠 AI 副业,1 个月实现月薪 3 万 +

    在物价飞涨.经济低迷的今天,仅靠死工资,却有着不固定的开销?房贷.车贷.孩子的教育费用-- 望着日益增长的开销,你是否也在夜深人静时,为钱包的羞涩而发愁?无数次幻想过拥有一份高收入的副业,却始终在迷茫 ...

  8. div剩余高度自动填充满

    这边采用弹性布局来处理 在需要被填充满的div上设置display:flex;,然后根据你所需要填充宽度(flex-direction:column;)高度(flex-direction:row;)设 ...

  9. docker - [14] redis集群部署

    本章节是在一个服务器上进行演示 一.准备工作 (1)创建redis集群使用的网络:redis-net docker network create redis-net --subnet 172.38.0 ...

  10. 【目标检测】一、初始的R-CNN与SVM

    1.流程 为什么要用SVM而不是CNN最后一层的softmax? 取什么模型必然是有标准衡量,这个流程取得是书上[4]写的,作者说他得实验证明SVM比FC的mAP要高,所以我流程暂且这样画了. R-C ...