C#编译器+通用代码与拳击+限制

让我们来看看以下的通用方法生成的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给出了一个小的开销(只是4X-5X慢),但为什么不发出更好的代码,在这种情况下?

--------------解决方案-------------

它看起来像编译器,因为与验证一些问题这一点。

你想编译器生成的IL是无法证实的,所以C#编译器不能生成它(的“不安全”的背景是可核查之外的所有C#代码)。

对于“验证类型的兼容性”的规则在第1.8.1.2.3中给出,对ECMA规范的Partion III。

他们说,一式“S”是检验一个类型的“T”或(S:= T)兼容使用以下规则:

  1. [:=是自反对于所有验证类型S,S:= S
  2. [:=传递性对于所有验证类型的S,T,和U当S:= T和T:= U,则S:= U.
  3. S:= T如果S是基类的T或T和T实现的接口是不是一个值类型。
  4. 对象:= T,如果T是一个接口类型。
  5. S:= T如果S和T是两个接口和T的实现需要S的实施
  6. S:= NULL,如果S是一个对象类型或接口
  7. S [] = T []如果S:= T和阵列或者是两个向量(从零开始,秩一),或者两者都不是一个载体,都具有相同的等级。 (该规则涉及阵列协方差。)
  8. 如果S和T是方法指针,则S:= T,如果签名(返回类型,参数类型和调用约定)是相同的。

这些规则的,这可能是适用在这种情况下,只有一个是#3。

然而,#3并不适用于你的代码,因为'U'是不是'T'一个基类,它是不是'T'的基本接口,所以“或”检查返回false。

这意味着,一些指令需要为了将装箱Ť成U中,将通过验证的方式来执行。

我同意你的验证规则应该改变,使生成您想要的代码实际上是可核实的。

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

你应该提交一个bug与别人微软。

这些制约因素看起来很奇怪:

where T : struct, U
where U : class

T是一个值类型,但在同一时间必须继承距离U是一个引用类型。 我不知道什么类型的能满足上述约束条件,使我们能够调用此方法。

分类:C# 时间:2015-03-15 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.332 (s). 10 q(s)