解决内联数组声明中的错误和警告

本文介绍了以下编译器错误和警告:

  • CS9164无法将表达式转换为 Span<T>,因为它不是可赋值变量
  • CS9165无法将表达式转换为 ReadOnlySpan<T>,因为它可能无法通过引用传递或返回
  • CS9166:索引超出内联数组的边界
  • CS9167:内联数组长度必须大于 0。
  • CS9168内联数组结构不得具有显式布局。
  • CS9169:内联数组结构必须且只能声明一个实例字段,该字段不得为 ref 字段。
  • CS9172只能使用可隐式转换为 intSystem.IndexSystem.Range 的单个参数访问内联数组类型的元素。
  • CS9173:内联数组访问可能没有已命名的参数说明符
  • CS9180内联数组元素字段不能声明为必需、只读、易失或固定大小缓冲区。
  • CS9181内联数组索引器不会用于元素访问表达式。
  • CS9182内联数组“Slice”方法不会用于元素访问表达式。
  • CS9183内联数组转换运算符不会用于从声明类型的表达式转换。
  • CS9184元素字段是“ref”字段,或者作为类型参数具有无效类型的内联数组类型不支持“内联数组”语言功能。
  • CS9189:不支持类型内联数组中的语句 foreach

内联数组声明

将内联数组声明为具有单个字段的 struct 类型,以及指定数组长度的属性。 编译器为无效的内联数组声明生成以下错误:

  • CS9167内联数组长度必须大于 0。
  • CS9168内联数组结构不得具有显式布局。
  • CS9169内联数组结构必须且只能声明一个实例字段,并且该字段不得为 ref 字段。
  • CS9180内联数组元素字段不能声明为必需、只读、易失或固定大小缓冲区。
  • CS9184元素字段是“ref”字段,或者作为类型参数具有无效类型的内联数组类型不支持“内联数组”语言功能。

若要修复这些数组,请确保满足以下条件:

  • System.Runtime.CompilerServices.InlineArrayAttribute 的参数是一个正整数。
  • 封闭 struct 没有指定任何显式布局。
  • 封闭 struct 具有单个实例字段,且该实例字段不是 ref 字段。
  • 单个实例字段不是固定大小缓冲区。
  • 单个实例字段不包括 requiredvolatilereadonly 修饰符。

元素访问

内联数组的元素访问方式与任何数组相同。 编译器会从不正确的元素访问中发出以下错误:

  • CS9166索引超出内联数组的边界
  • CS9172只能使用可隐式转换为 intSystem.IndexSystem.Range 的单个参数访问内联数组类型的元素。
  • CS9173内联数组访问可能没有命名参数说明符
  • CS9189:不支持类型内联数组中的语句 foreach

此外,编译器会在声明索引器时发出以下警告:

  • CS9181:内联数组索引器不会用于元素访问表达式。

内联缓冲区生成的代码可直接访问缓冲区内存,从而绕过任何声明的索引器。 内联数组不能与 foreach 语句一起使用。

索引器的参数必须是:

  • 以下三种类型之一:intSystem.IndexSystem.Range
  • 不能是命名参数。 编译器生成元素访问器。 参数没有名称,因此无法使用命名参数。
  • 在数组的边界内。 与所有 .NET 数组一样,内联数组元素访问也会进行边界检查。 索引必须位于内联数组的边界内。

转换为 Span

通常使用 System.Span<T>System.ReadOnlySpan<T> 来处理内联数组。 编译器针对无效转换生成以下错误:

  • CS9164无法将表达式转换为 Span<T>,因为它不是可赋值变量
  • CS9165无法将表达式转换为 ReadOnlySpan<T>,因为它可能无法通过引用传递或返回

编译器可生成直接访问内联缓冲区内存的代码。 因此,从未调用过某些成员。 如果编写了一个从未调用的成员,编译器将生成以下警告:

  • CS9182内联数组“Slice”方法不会用于元素访问表达式。
  • CS9183:内联数组转换运算符将不用于从声明类型的表达式转换。

内联数组可以隐式转换为 Span<T>ReadOnlySpan<T>,以将其传递给方法。 编译器对这些转换强制实施限制:

  • 内联数组必须可写入,以便转换为 Span<T>。 如果数组是只读数组,则无法将其转换为可写入的 Span<T>。 可以改用 ReadOnlySpan<T>
  • 内联数组的安全上下文必须至少与 Span<T>ReadOnlySpan<T>安全上下文一样宽,才能成功进行转换。 必须限制 Span 的上下文,或扩展内联数组的范围。

此外,编译器永远不会在内联缓冲区中生成对 Slice 方法的调用。 不会调用将内联缓冲区转换为 SpanReadOnlySpan 的转换运算符。 编译器会生成代码,以直接从内存缓冲区创建 System.Span<T>System.ReadOnlySpan<T>