为什么引用结构体不能用作类型参数?

16

C# 7.2 引入了 ref struct。 然而,如果有一个像这样的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
通用方法在另一个程序集中。它可能会执行任何你不允许使用ref结构体的操作。编译器无法验证你对该方法的描述是否在整个程序分析之外得到了保证。我猜测这种分析被认为是禁止的,因为它不能安全地完成,所以被禁止了。 - Mike Zboray
1个回答

7
ref struct 的主要保证是它永远不会逃逸到堆上。
在泛型方法中,编译器不验证无堆保证(因为几乎所有类型都可以存在于堆上)。防止泛型方法泄漏 ref struct 最简单的方法是禁止将 ref struct 用作类型参数,这就是 C# 所做的。
从 C# 7.2 开始,你可以在结构体类型的声明中使用 ref 修饰符。ref 结构体类型的实例分配在堆栈上,不能逃逸到托管堆。为了确保这一点,编译器限制使用 ref 结构体类型如下:
- ref 结构体不能是数组的元素类型。 - ref 结构体不能是类或非 ref 结构体的字段的声明类型。 - ref 结构体不能实现接口。 - ref 结构体不能装箱为 System.ValueType 或 System.Object。 - ref 结构体不能作为类型参数。 - ref 结构体变量不能被 lambda 表达式或本地函数所捕获。 - ref 结构体变量不能在异步方法中使用。但是,你可以在同步方法中使用 ref 结构体变量,例如,在返回 Task 或 Task<TResult> 的方法中。 - ref 结构体变量不能在迭代器中使用。
更多关于 ref struct 的详细信息,请访问Microsoft 的官方文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接