28

なぜこれが起こっているのか知りたいです。以下のコード例と、各セクションの下のコメントで発行された対応する 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最初のセクションではを出力callし、2 番目のセクションでは を出力したのはなぜですか? callvirtコンパイラが非仮想メソッドの命令を発行する理由はありますか? また、コンパイラがcallvirt非仮想メソッドに対して a を発行する場合がある場合、これは型安全性の問題を引き起こしますか?

4

5 に答える 5

23

安全に遊ぶだけです。

技術的には、C# コンパイラは常に使用するとは限りませんcallvirt

値型で定義された静的メソッドとメソッドの場合、call. 大部分はcallvirtIL 命令によって提供されます。

両者の間で投票を左右した違いcallは、「呼び出しを行うために使用されるオブジェクト」が null ではないことを前提としているという事実です。callvirt一方、null でないことを確認し、必要に応じて NullReferenceException をスローします。

  • 静的メソッドの場合、オブジェクトは型オブジェクトであり、null にすることはできません。値型についても同様です。したがってcall、それらに使用されます-パフォーマンスが向上します。
  • その他については、言語設計者が使用することを決定したcallvirtため、JIT コンパイラは、呼び出しを行うために使用されているオブジェクトが null でないことを確認します。非仮想インスタンス メソッドであっても、パフォーマンスよりも安全性を重視していました。

関連項目: Jeff Richter は、C# 2nd Ed を介した CLR の「型の設計」の章で、これについてより良い仕事をしています。

于 2009-05-10T17:32:20.347 に答える
3

(おそらく)興味深いことはさておき...そうではないGetType()という点で珍しいことです-これはいくつかの非常に奇妙なことにつながります. virtual

(実際の質問とは多少トピックが異なるため、wikiとしてマークされています)

于 2009-05-10T20:27:11.623 に答える