为啥 ref 结构不能用作类型参数?
Posted
技术标签:
【中文标题】为啥 ref 结构不能用作类型参数?【英文标题】:Why ref structs cannot be used as type arguments?为什么 ref 结构不能用作类型参数? 【发布时间】:2018-11-25 00:53:16 【问题描述】:C# 7.2 introducedref struct
s。但是,给定一个像这样的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
包的示例一样,该怎么办?为什么我不能在这些情况下将它们用作类型参数?
【问题讨论】:
泛型方法在另一个程序集中。它可能会做很多你不能用 ref structs 做的事情。在整个程序分析之外,编译器无法验证您所说的方法是否得到保证。我猜这样的分析被认为是禁止的,因为它不能安全地完成,所以它是不允许的。 【参考方案1】:ref struct
做出的主要保证是它永远不会逃到堆中。
在泛型方法中,编译器不会验证无堆保证(因为几乎所有类型都可以存在于堆上)。防止泛型方法泄漏ref struct
s 的最直接方法是简单地禁止使用ref struct
作为类型参数,这就是C# 所做的。
从 C# 7.2 开始,您可以在声明中使用 ref 修饰符 属于结构类型。 ref struct 类型的实例分配在 堆栈并且无法逃逸到托管堆。为确保, 编译器限制 ref struct 类型的使用如下:
ref struct 不能是数组的元素类型。 引用结构不能是类字段的声明类型或非引用结构。 ref struct 不能实现接口。 不能将 ref 结构装箱为 System.ValueType 或 System.Object。 引用结构不能是类型参数。 lambda 表达式或本地函数无法捕获 ref struct 变量。 不能在异步方法中使用 ref struct 变量。但是,您可以在同步方法中使用 ref struct 变量,例如, 在那些返回 Task 或 Task 的地方。 不能在迭代器中使用 ref struct 变量。
More details from Microsoft about ref structs
【讨论】:
以上是关于为啥 ref 结构不能用作类型参数?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们不能使用 CloudFormation 中的参数将 AllowedValues 用作字符串?