这个问题已经有一个答案在这里:

为什么一个通用的方法限制了T类会拳击说明,在产生集码?

我相当的惊讶,因为当然,由于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;
    }
}

这里就是产生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 
}

注意到 箱子!!T 说明。

为什么这是正在产生?

如何避免这种情况?

有帮助吗?

解决方案

你不需要担心任何性能下降,从 box 指令,因为如果其参数为基准类型, box 指令什么都不做。虽然这仍然很奇怪, box 指令甚至已经创建了(或许lazyiness/更容易设计代码生成的?).

其他提示

我不知道为什么任何拳击是ocurring.一个可能的办法避免的拳击是不要使用它。只是重新编译没有拳击。例如:

.assembly recomp_srp
{
    .ver 1:0:0:0
}

.class public auto ansi FixedPBF
{

.method public instance void .ctor() cil managed
{

}

.method hidebysig public instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed
{
    .maxstack 2    
        .locals init ( bool isDifferent, bool CS$4$0000)

        ldc.i4.0
        stloc.0
        ldarg.1
        ldobj !!T
        ldarg.2
        ceq
        stloc.1
        ldloc.1
        brtrue.s L_0001
        ldc.i4.1
        stloc.0
        L_0001: ret

}

}

...如果你保存一个文件recomp_srp.集你可以简单地重新编译为诸如:

ildasm/dll recomp_srp.集

它运行"确定"没有拳击在我结束:

        FixedPBF TestFixedPBF = new FixedPBF();

        TestFixedPBF.SetRefProperty<string>(ref TestField, "test2");

...当然,我改变了它从保护公众,你会需要作出的改变,并提供其余的执行情况。

我认为这是旨在通过设计。你不是约束T于特定类,因此这是最有可能下铸造它的对象。因此为什么你看到的IL包括拳击。

我会试试这个代码在哪里T:ActualClass

以下几点。首先,这一错误发生,对于这两种方法中的一个 一般类 与约束 where T : class 并且还 一般方法 有同样的约束(一般或非通用类)。它不会发生一(其他相同)非通用的方法,该方法使用 Object 而不是的 T:

// static T XchgNullCur<T>(ref T addr, T value) where T : class =>
//              Interlocked.CompareExchange(ref addr, val, null) ?? value;
    .locals init (!T tmp)
    ldarg addr
    ldarg val
    ldloca tmp
    initobj !T
    ldloc tmp
    call !!0 Interlocked::CompareExchange<!T>(!!0&, !!0, !!0)
    dup 
    box !T
    brtrue L_001a
    pop 
    ldarg val
L_001a:
    ret 


// static Object XchgNullCur(ref Object addr, Object val) =>
//                   Interlocked.CompareExchange(ref addr, val, null) ?? value;
    ldarg addr
    ldarg val
    ldnull
    call object Interlocked::CompareExchange(object&, object, object)
    dup
    brtrue L_000d
    pop
    ldarg val
L_000d:
    ret

注意到一些附加问题与第一个例子。而不是简单的 ldnull 我们有一个无关的 initobj 呼义目标的一个多余的地方变量 tmp.

好消息但是,暗示-在 在这里,, 是的,没有这一事项。尽管存在差异的IL产生的代码,用于上面的两个例子, 64JIT 产生几乎完全相同的代码。下面的结果。净框架4.7.2 释放模式 优化"不抑制".

enter image description here

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top