はじめに
これは私がILについて調べたことを忘れないようにメモする場所です。前提知識が確実に欠如しております。
間違いがございましたらご指摘お願いします。
特に明示しない場合は .NET Framework 4.8 を使い、規格はECMA-335に準ずるものとします。
どんどん更新していきます。(気分次第)
ジェネリクス
classC<T>{Tinst;}
のT
は!0
になる。よって上記のコードは
.class private auto ansi beforefieldinit C`1<T> extends [mscorlib]System.Object
{
.field private !0 inst
// .ctor 省略
}
簡単に書くと
.class private C`1<T>
{
.field private !0 inst
}
※C`1<T>
はC<T>
でもOK。ただし、class C<T>
とclass C
が両方あると.NET言語では片方しか参照できない。最初に書いた方が参照できる。
説明
ECMA-335 II.7.1 Typesでは、型定義のジェネリックパラメータは'!' Int32
、メソッド定義のジェネリックパラメータは'!!' Int32
となっている(Int32は0から数えたindex)。つまり、Class<T,U>.Method<V>()
があったとすると、T
は!0
、U
は!1
、V
は!!0
となる。
ちょいまてや
SharpLabで見てみるとldtoken !T
とかldtoken !!V
とかになってるじゃないですか! ldtoken !0
、ldtoken !!0
じゃないの?
ilasm.exe をつかうか
ilasm.exe で以下のようなコードをコンパイルしてみた。
.assembly extern mscorlib {}
.assembly generics.exe {}
.class public Program
{
.method static void Main()
{
.entrypoint
call class [mscorlib]System.Collections.Generic.List`1<!0> class C<int32>::GetList()
call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
call void [mscorlib]System.Console::WriteLine(object)
ret
}
}
.class public abstract sealed C`1<T>
{
.method public static class [mscorlib]System.Collections.Generic.List`1<!T> GetList()
{
newobj instance void class [mscorlib]System.Collections.Generic.List`1<!T>::.ctor()
ret
}
}
実行結果
System.Collections.Generic.List`1[System.Int32]
え、普通にいけるやん……。
ECMA-335ではこんな記法書いてなかったんだけどな……。
考察
T
→!T
なら、コンパイラ負荷は少なそう。- ソースコード→ILのコード→ILのバイナリーコード であればわざわざindex調べる必要がある
!0
や!!0
のような書き方より!T
、!!T
にした方がコンパイル速度も速そう。
- ソースコード→ILのコード→ILのバイナリーコード であればわざわざindex調べる必要がある
- IL(というかアセンブリ)は多様な書き方を許すべきであるはず。
- わざわざ
T
と名前がついているのにオペランドにT
を用いてはいけません、とする理由はない。
- わざわざ
!T
は型パラメータを指して、!0
は入力された型を指すのでは?call class [mscorlib]System.Collections.Generic.List`1<!T> class C<int32>::GetList()
ができないのかその証拠。!T
のList
を返すのではなく、!0
、つまりint32
のList
を返すのだから。call
命令の時点で型は決まっているから、抽象的な型パラメータを用いるのは間違っている。- ちなみに
call class [mscorlib]System.Collections.Generic.List`1<int32> class C<int32>::GetList()
は.method public static class [mscorlib]System.Collections.Generic.List`1<int32> GetList()
を指すため不可。