为什么带有T:class约束的泛型方法导致装箱?

Phi*_*hil 12 .net c# generics boxing

为什么将T限制为类的泛型方法会在生成MSIL代码中有装箱指令?

我对此感到非常惊讶,因为由于T被约束为引用类型,因此生成的代码不需要执行任何装箱.

这是c#代码:

protected void SetRefProperty<T>(ref T propertyBackingField, T newValue) where T : class
{
    bool isDifferent = false;

    // for reference types, we use a simple reference equality check to determine
    // whether the values are 'equal'.  We do not use an equality comparer as these are often
    // unreliable indicators of equality, AND because value equivalence does NOT indicate
    // that we should share a reference type since it may be a mutable.

    if (propertyBackingField != newValue)
    {
        isDifferent = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是生成的IL:

.method family hidebysig instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed
{
    .maxstack 2
    .locals init (
        [0] bool isDifferent,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldarg.1 
    L_0004: ldobj !!T
    L_0009: box !!T
    L_000e: ldarg.2 
    L_000f: box !!T
    L_0014: ceq 
    L_0016: stloc.1 
    L_0017: ldloc.1 
    L_0018: brtrue.s L_001e
    L_001a: nop 
    L_001b: ldc.i4.1 
    L_001c: stloc.0 
    L_001d: nop 
    L_001e: ret 
}
Run Code Online (Sandbox Code Playgroud)

注意方框!! T说明.

为什么要生成这个?

怎么避免这个?

Tho*_*ker 2

您不必担心该box指令会导致任何性能下降,因为如果其参数是引用类型,则该box指令不会执行任何操作。尽管box创建指令仍然很奇怪(也许是代码生成时的懒惰/更容易的设计?)。