T : 클래스의 제약 조건이있는 일반적인 방법은 권투를 초래합니까? [복제하다

StackOverflow https://stackoverflow.com/questions/1400414

  •  05-07-2019
  •  | 
  •  

문제

이 질문은 이미 여기에 답이 있습니다.

T에 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;
    }
}

생성 된 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 지시가 만들어졌습니다 (코드 생성시 게으른/더 쉬운 디자인).

다른 팁

권투가 왜 발생하는지 잘 모르겠습니다. 권투를 피하는 한 가지 가능한 방법은 권투를 사용하지 않는 것입니다. 권투없이 다시 컴파일하십시오. 전:

.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.msil 파일에 저장하면 다음과 같이 간단히 다시 컴파일 할 수 있습니다.

ildasm /dll recomp_srp.msil

그리고 그것은 내 끝에 권투없이 괜찮습니다.

        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 코드의 차이에도 불구하고 X64 JIT 거의 동일한 코드를 생성합니다. 다음과 같은 결과는 .NET 프레임 워크 4.7.2입니다 릴리스 모드 "억압되지 않은"최적화로.

enter image description here

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top