16

C# 7.2引入了 ref structs。但是,给定一个ref struct这样的:

public ref struct Foo {
  public int Bar;
}

我不能将它用作类型参数:

int i = 0;
var x = Unsafe.As<int, Foo>(ref i); // <- Error CS0306 The type 'Foo' may not be used as a type argument.

我知道 ref 结构只能存在于堆栈上,而不能存在于堆上。但是,如果保证使用此类 ref 结构的泛型方法永远不会将它们放在堆上,就像上面使用System.Runtime.CompilerServices.Unsafe包的示例中那样?为什么在这些情况下我不能将它们用作类型参数?

4

1 回答 1

5

a 做出的主要保证ref struct是它永远不会逃到堆中。

在泛型方法中,编译器不验证无堆保证(因为几乎所有类型都可以存在于堆上)。防止泛型方法泄漏ref structs 的最直接方法是简单地禁止使用 aref struct作为类型参数,这就是 C# 所做的。

从 C# 7.2 开始,您可以在结构类型的声明中使用 ref 修饰符。ref struct 类型的实例在堆栈上分配,不能逃逸到托管堆。为确保这一点,编译器将 ref struct 类型的使用限制如下:

  • ref struct 不能是数组的元素类型。
  • ref struct 不能是类字段或非 ref struct 的声明类型。
  • ref 结构不能实现接口。
  • 不能将 ref 结构装箱为 System.ValueType 或 System.Object。
  • ref 结构不能是类型参数。
  • lambda 表达式或本地函数无法捕获 ref struct 变量。
  • 不能在异步方法中使用 ref struct 变量。但是,您可以在同步方法中使用 ref struct 变量,例如,在返回 Task 或 Task 的方法中。
  • ref struct 变量不能在迭代器中使用。

Microsoft 提供的有关 ref 结构的更多详细信息

于 2020-10-07T15:32:01.397 回答