C# 컴파일러가 getType () 메소드 호출에 대한 CallVirt 명령을 방출하는 이유는 무엇입니까?

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

문제

왜 이런 일이 일어나고 있는지 궁금합니다. 아래 코드 예제와 각 섹션 아래의 의견에 방출 된 해당 IL을 읽으십시오.

using System;

class Program
{
    static void Main()
    {
        Object o = new Object();
        o.GetType();

        // L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        // L_0006: stloc.0 
        // L_0007: ldloc.0 
        // L_0008: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

        new Object().GetType();

        // L_000e: newobj instance void [mscorlib]System.Object::.ctor()
        // L_0013: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
    }
}

컴파일러가 방출 한 이유는 무엇입니까? callvirt 첫 번째 섹션의 경우 a call 두 번째 섹션은? 컴파일러가 callvirt 비가적인 방법에 대한 지시? 컴파일러가 방출하는 경우가있는 경우 callvirt 비가당한 방법의 경우 유형 안전에 문제가 발생합니까?

도움이 되었습니까?

해결책

그냥 안전한 연주.

기술적으로 C# 컴파일러는 그렇지 않습니다 언제나 사용 callvirt

값 유형에 정의 된 정적 메소드 및 메소드의 경우 사용합니다. call. 대다수는 callvirt IL 교육.

둘 사이에 투표를하는 차이점은 call "호출을하는 데 사용되는 개체"가 무효가 아니라고 가정합니다. callvirt 반면에 null이 아닌지 확인하고 필요한 경우 NullReferenceException을 던졌습니다.

  • 정적 메소드의 경우 객체는 유형 객체이며 Null이 될 수 없습니다. 가치 유형에 대한 ditto. 따라서 call 그들에게 사용됩니다 - 더 나은 성능.
  • 다른 사람들을 위해 언어 디자이너는 함께 가기로 결정했습니다. callvirt 따라서 JIT 컴파일러는 호출을 만드는 데 사용되는 객체가 널 있지 않다는 것을 확인합니다. 비 사건 적 인스턴스 방법의 경우에도 .. 성능보다 안전을 평가했습니다.

참조 : Jeff Richter는 C# 2nd ed를 통해 CLR의 '디자인 유형'장에서 더 나은 일을합니다.

다른 팁

보다 이것 Eric Gunnerson의 오래된 블로그 게시물.

게시물의 텍스트는 다음과 같습니다.

C#이 항상 CallVirt를 사용하는 이유는 무엇입니까?

이 질문은 내부 C# 별칭에 나타 났으며, 그 대답은 일반적인 관심사라고 생각했습니다. 그것은 대답이 정확하다고 가정합니다. 꽤 오랜 시간이 지났습니다.

.NET IL 언어는 Call 및 CallVirt 명령을 모두 제공하며 CallVirt는 가상 함수를 호출하는 데 사용됩니다. 그러나 C#이 생성하는 코드를 살펴보면 가상 기능이없는 경우에도 "Callvirt"가 생성되는 것을 알 수 있습니다. 왜 그렇게합니까?

나는 내가 가진 언어 디자인 노트를 거슬러 올라 갔으며, 그들은 1999 년 12 월 13 일에 Callvirt를 사용하기로 결정했다고 명확하게 진술했다. 불행히도, 그들은 우리의 이론적 근거를 포착하지 않으므로, 나는 내 기억에서 가야 할 것입니다.

우리는 누군가로부터 보고서를 받았습니다 (아마 이 방법이 필드에 액세스하지 않았기 때문에 예외는 (예 :“this”는 null이지만 사용 된 방법에서는 아무것도 사용하지 않았습니다). 그 방법은이 지점을 사용하여 예외를 던지는 다른 방법을 불렀으며 약간의 헤드 스크래치가 계속되었습니다. 그들이 그것을 알아 낸 후, 그들은 우리에게 그것에 대한 메모를 보냈습니다.

우리는 널 인스턴스에서 메소드를 호출 할 수 있다는 것이 약간 이상하다고 생각했습니다. 피터 골드 (Peter Golde)는 항상 Callvirt를 사용하는 PIRF 영향이 무엇인지 확인하기 위해 약간의 테스트를 수행했으며, 우리가 변화를하기로 결정한 것은 충분히 작았습니다.

(아마도) 흥미로운 옆으로 ... GetType() 그것에 대해 드문 일입니다 그렇지 않습니다 virtual - 이것은 일부로 이어집니다 매우 이상한 것들.

(실제 질문에 다소 주제가 아닌 위키로 표시)

컴파일러는 실제 유형을 모릅니다 o 첫 번째 표현식에서는 두 번째 표현식에서 실제 유형을 알고 있습니다. 한 번에 하나의 진술을보고있는 것 같습니다.

C#은 최적화를 위해 JIT에 크게 의존하기 때문에 이것은 괜찮습니다. 간단한 경우 두 통화가 런타임에 인스턴스 호출이 될 가능성이 매우 높습니다.

나는 믿지 않는다 callvirt 비가적인 방법에 대해서는 항상 방출되지만, 그렇지 않더라도, 그 방법이 결코 상인되지 않기 때문에 (명백한 이유로) 문제가되지 않을 것입니다.

나는 첫 번째가 변수에 할당되기 때문이라고 추측 할 것입니다. GetType (우리가 볼 수는 있지만 그렇지 않더라도); 두 번째는 결코 다른 것이 될 수 없습니다 Object.

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