gpt4 book ai didi

C# 编译器 + 带装箱的通用代码 + 约束

转载 作者:行者123 更新时间:2023-11-30 13:52:40 25 4
gpt4 key购买 nike

让我们检查一下为以下泛型方法生成的 MSIL 代码:

public static U BoxValue<T, U>(T value)
where T : struct, U
where U : class
{
return value;
}

看:

.method public hidebysig static !!U  BoxValue<valuetype .ctor
([mscorlib]System.ValueType, !!U) T,class U>(!!T 'value') cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: unbox.any !!U
IL_000b: ret
}

但对于上面的通用代码,更有效的 IL 表示应该是:

  IL_0000:  ldarg.0
IL_0001: box !!T
IL_0006: ret

从约束中得知值被装箱到引用类型Unbox.any 操作码是完全多余的,因为在 box 操作码之后,IL 堆栈中的值已经是对 !!U 的有效引用,可以无需任何拆箱即可使用。

为什么 C# 3.0 编译器不使用约束元数据来生成更高效的通用代码? Unbox.any 的开销很小(只慢 4 到 5 倍),但为什么不在这种情况下发出更好的代码呢?

最佳答案

看起来编译器这样做是因为验证器存在一些问题。

您希望编译器生成的 IL 不可验证,因此 C# 编译器无法生成它(“不安全”上下文之外的所有 C# 代码都应该是可验证的)。

“验证类型兼容性”的规则在 Ecma 规范的第 III 部分第 1.8.1.2.3 节中给出。

他们说类型“S”与类型“T”或 (S := T) 使用以下规则验证兼容:

  1. [:= is reflexive] 对于所有验证类型 S, S := S
  2. [:= 是可传递的] 对于所有验证类型 S、T 和 U,如果 S := T 和 T := U,则 S := U。
  3. S := T 如果 S 是 T 的基类或 T 实现的接口(interface)并且 T 不是值类型。
  4. object := T 如果 T 是接口(interface)类型。
  5. S := T 如果 S 和 T 都是接口(interface)并且 T 的实现需要实现的
  6. 如果 S 是对象类型或接口(interface),S := null
  7. S[] := T[] 如果 S := T 并且数组要么都是向量(从零开始,秩为一)要么都不是是一个向量,并且都具有相同的等级。 (此规则处理数组协方差。)
  8. 如果 S 和 T 是方法指针,则 S := T 如果签名(返回类型、参数类型和调用约定)相同。

在这些规则中,唯一可能适用于这种情况的规则是 #3。

但是,#3 不适用于您的代码,因为“U”不是“T”的基类,也不是“T”的基接口(interface),因此“或”检查返回 false。

这意味着需要执行一些指令,以便以能够通过验证程序的方式将装箱的 T 转换为 U。

我同意你的看法,应该更改验证规则,以便生成你想要的代码实际上是可验证的。

然而,从技术上讲,编译器正在根据 ECMA 规范做“正确”的事情。

您应该向 Microsoft 的某个人提交错误。

关于C# 编译器 + 带装箱的通用代码 + 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1661150/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com