命令の 16 進数の形式、MSIL (Microsoft Intermediate Language) アセンブリ形式、および簡単な説明の一覧を次の表に示します。
形式
|
アセンブリ形式
|
説明
|
|---|
FE 16 < T >
|
constrained.thisType | T 型に制約された型で仮想メソッドを呼び出します。
|
constrained プリフィックスが許可されるのは、callvirt 命令だけです。
この時点での MSIL スタックは、次のような状態であることが必要です。
マネージ ポインタ ptr がスタックにプッシュされます。ptr の型は、thisType へのマネージ ポインタ (&) であることが必要です。これは、thisType の参照を必要とする、プリフィックスのない callvirt 命令の場合とは異なります。
プリフィックスのない callvirt 命令を使用した場合と同様に、メソッド引数の arg1 から argN までがスタックにプッシュされます。
constrained プリフィックスは、thisType が値型か参照型かを問わず、callvirt 命令を一貫した方法で実行できるようにデザインされています。
callvirt method 命令にプリフィックスとして constrained thisType を付けた場合、命令は次のように実行されます。
thisType が値型ではなく参照型の場合、ptr は逆参照され、method の callvirt への 'this' ポインタとして渡されます。
thisType が値型であり、thisType が method を実装している場合、ptr は thisType による method の実装に対して、call method 命令への 'this' ポインタとして変更されない状態で渡されます。
thisType が値型であり、thisType が method を実装していない場合、ptr は逆参照され、ボックス化されて、callvirt method 命令への 'this' ポインタとして渡されます。
この最後のケースは、method が Object、ValueType、または Enum で定義され、しかも thisType によってオーバーライドされていない場合にだけ発生する可能性があります。この場合、ボックス化によって元のオブジェクトのコピーが作成されます。ただし、Object、ValueType、および Enum のどのメソッドもオブジェクトの状態を変更しないため、これを検出することはできません。
constrained プリフィックスは、ジェネリック コードを作成する IL ジェネレータをサポートしています。通常、callvirt 命令は値型では有効ではありません。代わりに、IL コンパイラが ptr の型および呼び出されるメソッドに応じて、コンパイル時に前述の 'this' 変換を効率的に実行することが必要となります。ただし、ptr がコンパイル時には未知のジェネリック型の場合、コンパイル時にこの変換を行うことはできません。
constrained オペコードによって、ptr が値型か参照型かを問わず、IL コンパイラは一貫した方法で仮想関数の呼び出しを行うことができます。constrained プリフィックスは、thisType がジェネリック型の変数である場合を対象としていますが、非ジェネリック型に対しても機能するため、値型と参照型の区別を隠す言語で仮想呼び出しを生成する際の複雑さを軽減できます。
constrained プリフィックスを使用すると、値型でバージョン管理の問題が発生する可能性も回避できます。constrained プリフィックスを使用しない場合、値型が System.Object のメソッドをオーバーライドするかどうかに応じて異なる IL を出力する必要があります。たとえば、値型 V が Object.ToString() メソッドをオーバーライドする場合は、call V.ToString() 命令を出力し、オーバーライドしない場合には、box 命令と callvirt Object.ToString() 命令を出力します。バージョン管理の問題は、オーバーライドしたときにオーバーライドが後で削除された場合、およびオーバーライドしなかったときにオーバーライドが後で追加された場合に発生する可能性があります。
インターフェイス メソッドを実装している値型メソッドは、MethodImpl を使用して変更できるため、値型に対してインターフェイス メソッドを呼び出す場合にも、constrained プリフィックスを使用できます。constrained プリフィックスを使用しない場合、コンパイラはバインド先となる値型のメソッドをコンパイル時に選択するよう強制されます。constrained プリフィックスを使用すると、MSIL はコンパイル時ではなく、実行時にインターフェイス メソッドを実装するメソッドにバインドすることが可能になります。
constrained オペコードを使用できる Emit メソッド オーバーロードを次に示します。