C#编译器+的通用代码拳击+约束
题
让我们检查集产生的代码,用于以下通用的方法:
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
操作的价值在伊堆已经将是一个有效的参考 !!U
, 可以使用没有任何拆箱.
为什么不C#3.0编译器不使用限制的元数据以发出更有效的通用代码?拆箱.任何使一个小的开销,(仅有4-5倍的速度较慢),但为什么不发更好的代码,在这种情况?
解决方案
它看起来像编译器,这是否因为一些问题与验证程序。
伊尔,你会喜欢的编译器产生的是不可核查的,因此C#编译器不能产生(C#外的代码"不安全"背景下应该可以核查).
规则"的核查类型兼容性"的部分中给出的1.8.1.2.3,部分三的通信机制详解的规范。
他们说,这一类型的"S"是验证兼容类型的'T'或(S:=T)使用下列规则:
- [:=是反思的]所有的核查类型,S:=S
- [:=是传递的]所有的核查类型S,T、U如果S:=T和T:=U,那么S:=U.
- S=T如果是基类的T或一个接口实现的T和T不是一个值的类型。
- 对象:=T如果T是一个接口的类型。
- S=T如果S和T两个接口,并实施T要求的执行情况 S
- S=null如果一个目的类型或一个接口
- S[]:=T[]如果S:=T和阵列是两个载体(基于零,职级一)或两者都不是 是一个矢量和两者具有相同的等级。(这条规则涉及列协方差。)
- 如果S和T方法的指针,那么S:=T如果签字(回归类型、参数和类型 呼吁《公约》)是相同的。
这些规则,只有一个可适用于这种情况下为#3.
然而,#3不适用于代码,因为'U'不是一个基类的'T',并且它不是一个基本界面的'T',所以'或'检查返回错误的。
这意味着一些指令需要进行执行了转换一个装箱T U的方式,将通过检验器。
我会同意你的看法,核查规定应该改变,因此,产生的代码你想要的是实际上可以核查的。
从技术上讲,但是,编译器是做"正确的"的事情基础的通信机制详解的规范。
你应该文件的一个错误的人。
其他提示
这些约束看起来很奇怪:
where T : struct, U
where U : class
T为值类型,但在相同的时间必须距离U是一个引用类型继承。我不知道什么类型能够满足上述限制,并允许我们调用此方法。
不隶属于 StackOverflow