safe上下文关键字证明声明在更新的内存安全模型要求你明确做出安全选择的地方是健全的。 在编译器无法自行分类的声明上应用 safe 修饰符,例如 extern 具有显式布局的结构中的成员或字段。
safe修饰符是: unsafesafe证明调用方不需要unsafe上下文,同时unsafe向调用方传播审核安全的义务。
Important
关键字safe是更新的内存安全模型的一部分,它是 C# 15 和 .NET 11 中的预览功能。 编译器接受 safe 作为成员和显式布局字段的 extern 修饰符。 但是,更新的调用方安全规则没有公开选择加入,因此编译器不会强制实施安全选择 safe ,并 unsafe 表示:省略这两个修饰符不会产生错误,并且两个修饰符都无法更改调用方可以执行的操作。 若要遵循该功能,请将 LangVersion 编译器选项设置为 preview。 有关完整设计,请参阅 内存安全功能规范。
Extern 成员
成员 extern 调用本机代码,因此编译器无法对其安全性进行分类。 在更新的模型中,将标记每个extern声明,包括分LibraryImport部方法,或safeunsafe:
// Compiles under LangVersion preview, but the safety choice isn't enforced yet.
[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)]中,字段可以在内存中重叠,因此编译器无法解释读取一个字段是否为声音。 标记此类结构的每个字段或safeunsafe:
// Compiles under LangVersion preview, but the safety choice isn't enforced yet.
[StructLayout(LayoutKind.Explicit)]
internal struct Union
{
[FieldOffset(0)]
internal safe int AsInt;
[FieldOffset(0)]
internal safe float AsFloat;
}
保存本机指针的字段,或者其类型具有类型系统无法表示的固定类型为 unsafe。 类型系统完全描述其类型的字段。safe 与 extern 成员一样,省略这两个修饰符的目的是在更新的模型中出错,但编译器尚未强制实施该规则。
C# 语言规范
有关详细信息,请参阅 C# 语言规范中的不安全代码。 语言规范是 C# 语法和用法的明确来源。
有关更新的内存安全模型的设计,请参阅 内存安全功能规范。