1

int以下の例では、値型 ( )で仮想メソッドを呼び出します。

namespace ShortTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 42;
            i.ToString();
            ((object)i).ToString();
        }
    }
}

Reflector で生成された CIL を見ると、次の 2 つの呼び出しのコードが表示されます。

.locals init ([0] int32 i, ...)
...
L_001a: ldloca.s i
L_001c: call instance string [mscorlib]System.Int32::ToString()
L_0021: pop
L_0022: ldloc.0
L_0023: box int32
L_0028: callvirt instance string [mscorlib]System.Object::ToString()
L_002d: pop
...

パラメーターは、最初のケースでは int へのthisマネージ ポインターであり、2 番目のケースではボックス化されたint(つまり、ヘッダー フィールドと int フィールドを持つオブジェクトへのポインター) への参照です。

両方の呼び出し ( intimplements ToString()) に同じメソッドが使用されるため、これはどのように機能するのでしょうか? このSystem.Int32::ToString()メソッドはポインタを使用ldind.i4しての値を取得するため、最初のケースでは の値を取得する必要がありますが、2 番目のケースでは boxedの最初のフィールド (ヘッダー) の値を取得する必要があります。thisintintint

L_0000: ldarg.0
L_0001: ldind.i4
...
4

1 に答える 1

3

ただし、2 番目のケースでは、ボックス化された int の最初のフィールド (ヘッダー) の値を取得する必要があります。

ToStringメソッドにポインターが渡され、たまたまポイントされているバイトが読み取られると想定しています。その仮定は間違っています。

値型のインスタンス メソッドは、ref T"this" パラメーターがあるかのように動作します。.NET ランタイムは、値の型がボックス化されているかどうかに関係なく、これが正しく渡されることを確認するため、メソッドはボックス化された値に特別な処理を与える必要がありません。

あなたの出発点は正しいです:

I.8.9.7 値型の定義

非静的メソッド (つまり、インスタンスまたは仮想メソッド) が値の型で呼び出されると、その this ポインターはインスタンスへのマネージド参照になりますが、メソッドが関連するボックス化された型で呼び出されると、this ポインターはオブジェクト参照。

ldind.i4ただし、これは、同じ命令が関係なく機能するように発生します。アンマネージ ポインターを参照する場合にのみ、単純にバイトを読み取ります。

あなたが見つけた

II.13.3 値型のメソッド

クラスのインスタンス メソッドと仮想メソッドは、クラスのインスタンスへの参照を this ポインターとして想定するようにコーディングする必要があります。対照的に、値型のインスタンス メソッドと仮想メソッドは、値型のボックス化されていないインスタンスへのマネージ ポインター (パーティション I を参照) を予期するようにコーディングする必要があります。ボックス化された値の型が、ボックス化されていない値の型によって実装が提供される仮想メソッドへの this ポインターとして渡されると、CLI はボックス化された値の型を非ボックス化された値の型へのマネージド ポインターに変換します。

これは一見すると上記と矛盾しますが、実際には、実装はそれを機能させるために必要な魔法を単純に使用する必要があると述べています。

于 2013-02-28T10:14:24.900 に答える