通过


解决不安全代码构造中的错误和警告

本文介绍以下编译器诊断:

  • CS0193* 或 -> 运算符必须应用于指针
  • CS0196指针必须仅索引一个值
  • CS0208无法获取地址、获取其大小或声明指向托管类型的指针('type')
  • CS0209语句中 fixed 声明的本地类型必须是指针类型
  • CS0210必须在fixed或在using语句声明中提供初始值设定项
  • CS0211无法获取给定表达式的地址
  • CS0212只能在fixed语句的初始化程序中获取未被固定的表达式的地址
  • CS0213不能使用 fixed 语句获取已固定表达式的地址
  • CS0214指针和固定大小的缓冲区只能在不安全的上下文中使用
  • CS0227仅当使用 /unsafe 进行编译时,才会显示不安全代码
  • CS0233“identifier”没有预定义的大小,因此 sizeof 只能在不安全的上下文中使用
  • CS0242该操作在 void 指针上未定义
  • CS0244is”和“”as在指针类型上都无效
  • CS0254固定语句赋值右侧不能是强制转换表达式
  • CS0459无法获取只读局部变量的地址
  • CS0821无法修复隐式类型局部变量
  • CS1641固定大小缓冲区字段必须在字段名称后面具有数组大小说明符
  • CS1642固定大小缓冲区字段只能是结构的成员。
  • CS1656无法分配给“variable”,因为它是“只读变量类型”
  • CS1663固定大小的缓冲区类型必须是以下类型之一:bool、、byteshortintlong、、char、、sbyteushortuint、或 ulongfloatdouble
  • CS1665固定大小缓冲区的长度必须大于零
  • CS1666不能使用未固定表达式中包含的固定大小缓冲区。请尝试使用固定语句。
  • CS1708固定大小缓冲区只能通过局部变量或字段访问
  • CS1716请勿使用“System.Runtime.CompilerServices.FixedBuffer”属性。请改用“固定”字段修饰符。
  • CS1919对象创建中不能使用不安全类型“类型名称”。
  • CS4004在不安全的上下文中无法await
  • CS7092固定缓冲区可能只有一个维度。
  • CS8372不要对属性使用“System.Runtime.CompilerServices.FixedBuffer”属性
  • CS8812无法将 &method 组“method”转换为非函数指针类型“type”。
  • CS9049固定字段不能是 ref 字段。
  • CS9123&“运算符不应用于异步方法中的参数或局部变量。
  • CS9360此操作只能在不安全的上下文中使用
  • CS9361stackalloc 没有初始值设定项的 SkipLocalsInit 表达式只能在不安全的上下文中使用
  • CS9362必须在不安全的上下文中使用“member”,因为它被标记为“”RequiresUnsafe或“extern
  • CS9363“成员”必须在不安全的上下文中使用,因为它的签名中具有指针
  • CS9364不安全的成员“member”无法替代安全成员“member”
  • CS9365不安全的成员“member”无法隐式实现安全成员“member”
  • CS9366不安全的成员“member”无法实现安全成员“member”
  • CS9367RequiresUnsafeAttribute 不能应用于此符号。
  • CS9368RequiresUnsafeAttribute 仅在更新的内存安全规则下有效。
  • CS9376: 构造函数“constructor”标记为RequiresUnsafeextern,需要在不安全的上下文中使用,以满足“generic type or method”中类型参数“type parameter”的“new()”约束
  • CS9377unsafe”修饰符在当前内存安全规则下没有任何影响。

指针操作和解引用

  • CS0193*->运算符必须应用于指针
  • CS0196指针必须仅索引一个值
  • CS0242所涉及的操作在 void 指针上是未定义的

若要正确使用指针作,请遵循取消引用、索引和算术运算的规则。 有关详细信息,请参阅指针类型和函数指针

  • 仅将 *-> 运算符应用于数据指针(CS0193)。 不要将这些运算符用于非点器类型或函数指针。 与 C/C++ 不同,无法在 C# 中取消引用函数指针。
  • 仅包含一个值的索引指针(CS0196)。 指针不支持多维索引。
  • 避免在 void 指针(CS0242)上执行未定义的操作。 例如,不要递增 void 指针,因为编译器不知道要指向的数据的大小。

指针类型和托管类型

  • CS0208不能取得托管类型('type')的地址、大小,或声明其指针
  • CS0233“identifier”没有预定义的大小,因此 sizeof 只能在不安全的上下文中使用

若要正确处理指针和 sizeof 运算符,请使用非托管类型和正确的上下文。 有关详细信息,请参阅非托管类型和sizeof运算符

  • 仅对非托管类型(CS0208)使用指针。 不要获取托管类型的地址、获取其大小或声明指向托管类型的指针。 托管类型包括引用类型和包含引用类型字段或属性的结构。
  • 在大小不是编译时常量(sizeof)的类型的unsafe上下文中使用运算符。

固定语句用法

  • CS0209固定语句中声明的本地类型必须是指针类型
  • CS0210必须在固定声明或 using 语句声明中提供初始值设定项
  • CS0211无法获取给定表达式的地址
  • CS0212只能在固定语句的初始化器中获取未固定的表达式的地址
  • CS0213不能使用固定语句获取已固定表达式的地址
  • CS0254固定语句赋值右侧可能不是强制转换表达式
  • CS0459无法获取只读局部变量的地址
  • CS0821无法修复隐式类型局部变量
  • CS1656无法分配给“variable”,因为它是“只读变量类型”

错误地使用 fixed 语句 时,会发生这些错误。 该 fixed 语句可防止垃圾回收器重新定位可移动变量并声明指向该变量的指针。 有关详细信息,请参阅 不安全的代码和指针

要正确使用 fixed 语句:

  • 将变量声明为指针类型(CS0209)。
  • fixed 语句声明中提供初始化器(CS0210)。
  • 仅获取有效表达式的地址:字段、局部变量和指针间接(CS0211)。 不要采用计算表达式的地址,如两个变量的总和。
  • 仅在语句初始值设定项(fixed)中使用未修复表达式的地址运算符。
  • 不要对已修复的表达式使用 fixed 语句(CS0213)。 方法中的 unsafe 局部变量和参数已经固定在堆栈上。
  • 不要在fixed语句赋值的右侧使用强制转换表达式(CS0254)。
  • 不要获取只读局部变量(CS0459)的地址。 foreach 循环、using 语句和fixed 语句中的变量是只读的。 此错误不再由编译器的当前版本生成。
  • 使用显式类型而非在 var 语句中使用 fixed (CS0821)。
  • 不要在只读上下文(如 foreach 循环、 using 语句或 fixed 语句(CS1656)中分配给变量。

不安全的上下文要求

  • CS0214指针和固定大小缓冲区只能在不安全的上下文中使用
  • CS0227仅当使用 /unsafe 进行编译时,才会显示不安全代码
  • CS0244is”和“”as在指针类型上都无效
  • CS1919创建对象时无法使用不安全类型“类型名称”
  • CS4004在不安全的上下文中无法await
  • CS9123&“运算符不应用于异步方法中的参数或局部变量
  • CS9360此操作只能在不安全的上下文中使用
  • CS9361stackalloc 没有初始值设定项的 SkipLocalsInit 表达式只能在不安全的上下文中使用
  • CS9362必须在不安全的上下文中使用“member”,因为它被标记为“”RequiresUnsafe或“extern
  • CS9363必须在不安全的上下文中使用“member”,因为它的签名中具有指针
  • CS9376构造函数“constructor”标记为“RequiresUnsafe”或“extern”需要不安全的上下文,以满足“泛型类型或方法”中类型参数“type parameter”的“new()”约束

未使用所需的unsafe上下文而使用不安全代码构造,或者尝试未被允许的对不安全类型进行的操作时,会生成这些诊断信息。 有关详细信息,请参阅 不安全代码和指针 以及 unsafe 关键字

  • 标记使用指针或固定大小缓冲区的方法、类型或代码块,使用关键字 unsafeCS0214)。 对于任何使用指针类型或固定大小的缓冲区字段的代码,编译器都需要显式不安全的上下文。
  • 在项目设置(CS0227)中启用 AllowUnsafeBlocks 编译器选项。 如果没有此选项,即使代码正确,编译器也会拒绝所有 unsafe 块。
  • 不要在指针类型中使用isas运算符(CS0244)。 这些类型测试运算符对指针无效,因为指针不参与类型层次结构。
  • 请勿使用 new 运算符创建指针类型实例(CS1919)。 若要在非托管内存中创建对象,请使用互操作调用返回指针的原生方法。
  • 将不安全代码与异步代码(CS4004)分开。 编译器不允许 await 块内的 unsafe 表达式,因为运行时无法保证挂起点的指针有效性。 为不安全的操作创建单独的方法,并在异步方法中调用它们。
  • 不要对异步方法(&)中的参数或局部变量使用地址运算符()。 当异步操作在挂起点后恢复时,堆栈中可能不存在该变量。
  • 使用关键字(unsafe)标记涉及不安全构造(例如指针取消引用、地址为非托管类型的操作)(CS9360)。 在 C# 15 更新的内存安全规则下,编译器标识需要不安全上下文的各个操作。
  • 在应用 SkipLocalsInit 属性时,对于 stackalloc 没有初始值设定项的表达式,请使用 unsafe 关键字(CS9361)。 如果没有初始值设定项,堆栈分配的内存将包含未初始化的数据,这是不安全的操作。
  • 在调用标记为RequiresUnsafeextern的成员(CS9362)时,请使用unsafe上下文,或调用签名中具有指针的成员(CS9363)。 C# 15 编译器跟踪调用站点上的不安全成员使用情况,而不仅仅是声明。
  • unsafenew()约束需要调用标记为RequiresUnsafeextern的构造函数(CS9376)时,请使用上下文环境。 泛型实例化隐式调用构造函数,因此调用上下文必须不安全。

不安全的成员安全协定

  • CS9364不安全的成员“member”无法替代安全成员“member”
  • CS9365不安全的成员“member”无法隐式实现安全成员“member”
  • CS9366不安全的成员“member”无法实现安全成员“member”
  • CS9367RequiresUnsafeAttribute 不能应用于此符号。
  • CS9368RequiresUnsafeAttribute 仅在更新的内存安全规则下有效。
  • CS9377unsafe”修饰符在当前内存安全规则下没有任何影响。

这些诊断对标记为不安全的成员强制实施 C# 15 安全协定规则。 编译器确保不安全的成员不会违反基类和接口建立的安全期望。 有关详细信息,请参阅 不安全代码和指针 以及 unsafe 关键字

  • 不要用不安全的成员重载安全的基成员(CS9364)。 替代必须保留基本成员的安全协定。 如果基成员是安全的,则重写也必须是安全的。 从重写成员中删除unsafe修饰符或RequiresUnsafeAttribute,或者将基成员标记为不安全。
  • 不要隐式实现具有不安全成员(CS9365)的安全接口成员。 当类型隐式实现接口成员时,接口调用者期望安全操作。 从实现成员中删除不安全的指定,或使用显式接口实现。
  • 不要显式实现具有不安全成员的安全接口成员(CS9366)。 即使使用显式实现,也必须保留接口成员的安全协定。
  • 仅适用于 RequiresUnsafeAttribute 支持的符号类型(CS9367)。 此属性可以应用于方法、属性、事件、构造函数和类型,但并非所有符号类型都支持它。
  • 启用更新后的内存安全规则以使用 RequiresUnsafeAttributeCS9368)。 此属性是 C# 15 优化内存安全模型的一部分,在旧规则下无法识别。 请确保您的项目目标是支持更新规则的语言版本。
  • 删除unsafe修饰符在无效时(CS9377)。 根据当前的内存安全规则,某些上下文不需要或受益于 unsafe 修饰符。 编译器在修饰符毫无意义时发出警告,以便清理不必要的批注。

固定大小的缓冲区

  • CS1641固定大小缓冲区字段必须在字段名称后面具有数组大小说明符
  • CS1642固定大小缓冲区字段只能是结构的成员
  • CS1663固定大小的缓冲区类型必须是以下类型之一:bool、、byteshortintlong、、char、、sbyteushortuint、或 ulongfloatdouble
  • CS1665固定大小缓冲区的长度必须大于零
  • CS1666不能使用未固定表达式中包含的固定大小缓冲区。尝试使用固定语句
  • CS1708固定大小缓冲区只能通过局部变量或字段访问
  • CS1716请勿使用“System.Runtime.CompilerServices.FixedBuffer”属性。改用“固定”字段修饰符
  • CS7092固定缓冲区可能只有一个维度。
  • CS8372不要对属性使用“System.Runtime.CompilerServices.FixedBuffer”属性
  • CS9049固定字段不能是 ref 字段

使用固定大小的缓冲区时,会发生这些错误。 固定大小的缓冲区是直接嵌入在结构中的数组,主要用于互作方案。 有关详细信息,请参阅 固定大小的缓冲区

若要正确声明和使用固定大小的缓冲区,请执行以下作:

  • 使用正整数常量(CS1641CS1665)在字段名称后面指定数组大小。
  • 仅在结构中声明固定大小的缓冲区,而不是在类中(CS1642)。 如果需要类中的字段,请使用常规数组。
  • 使用受支持的元素类型之一:bool、、byteshortintlongcharsbyteushortuintulong、或 floatdoubleCS1663)。
  • 在访问缓冲区之前使用fixed语句来固定包含结构(CS1666)。
  • 仅通过局部变量或字段(而不是中间表达式(CS1708)访问固定大小的缓冲区。
  • fixed使用字段修饰符而不是System.Runtime.CompilerServices.FixedBuffer属性(CS1716)。 不要将此属性应用于属性(CS8372)。
  • 声明只有一个维度的固定缓冲区(CS7092)。 不支持多维固定缓冲区。
  • 不要将固定大小的缓冲区声明为 ref 字段(CS9049)。 固定大小的缓冲区必须是值字段。

函数指针

  • CS8812无法将 &method 组“method”转换为非函数指针类型“type”。

若要获取函数指针,请使用地址运算符,并显式转换为函数指针类型。 请勿使用 地址运算符 & 将方法组 void* 分配给其他非函数指针类型。 有关详细信息,请参阅 函数指针