safe (C# 参考)

上下文 safe 关键字将声明标记为不需要 unsafe 在 更新的内存安全模型中使用站点的上下文。 safe修饰符是与 . 的unsafe对应项。 声明的调用方 safe 不需要不安全的上下文,同时 unsafe 向调用方传播审核安全的义务。

safe即使调用方不需要unsafe上下文,使用关键字本身也需要AllowUnsafeBlocks编译器选项(-unsafe)。 默认情况下,普通声明是安全的,因此省略 safe 不需要避免不必要的不安全编译。

Important

关键字safe是更新的内存安全模型的一部分,它是 C# 15 和 .NET 11 中的预览功能。 preview设置为LangVersion启用语法。 若要强制实施更新的规则,包括显式 safe 或 unsafe 选择,并要求不安全的 updated-memory-safety-rules 调用方义务,请启用编译器功能。 有关激活详细信息,请参阅 “启用更新的内存安全规则”。 有关完整设计,请参阅 内存安全功能规范。

允许和必需的声明

可以应用于 safe 允许要求不安全的修饰符的声明,包括方法、构造函数、属性和字段。 对于普通声明,修饰符可以明确预期协定,包括在源代码生成的代码中。 它不限于 extern 成员和布局字段。

某些声明需要显式选择 safe 或 unsafe 启用更新的规则的时间。 以下部分介绍 extern 成员和显式布局字段或扩展布局字段。

与不同 unsafe, safe 不建立词法上下文。 它不会使成员正文中的不安全操作安全或取消封闭的不安全上下文。 不能在同一声明中合并 safe 和 unsafe 修饰符;这样做会生成 CS9388。

在较新的编译器中, safe 声明也需要 AllowUnsafeBlocks,即使调用方不需要不安全的上下文。 在项目文件中设置 <AllowUnsafeBlocks>true</AllowUnsafeBlocks> 以解析 CS9401。 此修饰符检查独立于更新的规则强制加入。 Roslyn 在 Visual Studio 2026 版本 18.13 中介绍,.NET 11.0.100 之后,.NET 11 RC2 编译器不会强制实施此要求safe。 有关编译器边界以及 与 CS0227 在不安全块上的区别,请参阅 不安全上下文要求。

Extern 成员

成员 extern 调用本机代码,因此编译器无法对其安全性进行分类。 在更新的模型中,将标记每个extern声明,包括分LibraryImport部方法,或safeunsafe:

// Syntax requires LangVersion preview; enforcement requires the updated-memory-safety-rules compiler feature.
[LibraryImport("libc")]
internal static safe partial int getpid();

[LibraryImport("libc", StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial nint strlen(byte* str);

getpid 不采用任何参数并返回一个基元,因此作者证明调用是安全的,并且调用方在没有上下文的情况下 unsafe 使用它。 strlen 获取本机代码取消引用的原始指针,因此声明是 unsafe 并将义务传播给调用方。 启用更新的规则后,省略这两个修饰符是一个错误。

显式或扩展布局字段

在类型中 [StructLayout(LayoutKind.Explicit)] ,编译器 [ExtendedLayout]不能自行对每个实例字段的安全进行分类。 您可以标记每个此类字段, safe 或者 unsafe:

// Syntax requires LangVersion preview; enforcement requires the updated-memory-safety-rules compiler feature.
[StructLayout(LayoutKind.Explicit)]
internal struct Union
{
    [FieldOffset(0)]
    internal safe int AsInt;

    [FieldOffset(0)]
    internal safe float AsFloat;
}

保存本机指针的字段,或者其类型具有类型系统无法表示的固定类型为 unsafe。 类型系统完全描述其类型的字段。safe 同一规则适用于显式布局字段和扩展布局字段。 与 extern 成员一样,启用更新的规则时省略这两个修饰符是一个错误。

将相同的修饰符应用于具有非零 StructLayoutAttribute.Pack 或 StructLayoutAttribute.Size包括顺序和自动布局的类型中的实例字段。 例如,具有相同显式选择的顺序布局类型 Pack = 1 。 未指定或零值不会自行触发其他规则。 静态字段和常量字段是豁免的。 对于合成后盾字段,请将修饰符置于拥有属性或事件上。

有关其他合成存储的 CS9392 消息和修补程序,请参阅 字段布局安全性。

C# 语言规范

有关详细信息,请参阅 C# 语言规范中的不安全代码。 语言规范是 C# 语法和用法的明确来源。

有关更新的内存安全模型的设计,请参阅 内存安全功能规范。

另见