コンストラクタ・イベント
コンストラクタ
インスタンスコンストラクタ
- .ctor
- 参照型の場合、引数なしのコンストラクタは自動的に生成される
- インライン初期化したフィールドは、コンパイル時にインスタンスコンストラクタコードに自動変換される。
- コンストラクタの数だけ重複した初期化ロジックが生成されることになるので、フィールドは宣言だけにとどめるほうがコードサイズの削減になる。
class FooClass { private int a_; private int b_ = 10; public FooClass(int b) { b_ = b; } public FooClass(int a, int b) { a_ = a; b_ = b; } }
試しにこういうクラスのILコードを覗く。
.method public hidebysig specialname rtspecialname instance void .ctor(int32 b) cil managed { // コード サイズ 25 (0x19) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.s 10 IL_0003: stfld int32 ConsoleApplication3.FooClass::b_ IL_0008: ldarg.0 IL_0009: call instance void [mscorlib]System.Object::.ctor() IL_000e: nop IL_000f: nop IL_0010: ldarg.0 IL_0011: ldarg.1 IL_0012: stfld int32 ConsoleApplication3.FooClass::b_ IL_0017: nop IL_0018: ret } // end of method FooClass::.ctor .method public hidebysig specialname rtspecialname instance void .ctor(int32 a, int32 b) cil managed { // コード サイズ 32 (0x20) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.s 10 IL_0003: stfld int32 ConsoleApplication3.FooClass::b_ IL_0008: ldarg.0 IL_0009: call instance void [mscorlib]System.Object::.ctor() IL_000e: nop IL_000f: nop IL_0010: ldarg.0 IL_0011: ldarg.1 IL_0012: stfld int32 ConsoleApplication3.FooClass::a_ IL_0017: ldarg.0 IL_0018: ldarg.2 IL_0019: stfld int32 ConsoleApplication3.FooClass::b_ IL_001e: nop IL_001f: ret } // end of method FooClass::.ctor
両方のコンストラクタにフィールドb_初期化のILコードが生成されている。
タイプコンストラクタ
JITコンパイラによるタイプコンストラクタ呼出の挿入
2つの選択肢がある。
- preciseセマンティクス
- CLRが正確に決められたタイミングで呼び出す。
- before-field-initセマンティクス
- 継承されないstaticフィールドへのアクセス実行前のどこかに挿入。
- 呼び出すタイミングとして自由度が高く、CLRにとって高速に実行できるコードが生成できる。
規定ではコンパイラによってセマンティクスは決定される。
判断結果として、型定義メタデータにbeforefieldinitメタデータフラグを付ける。(これによりCLRへ通知する)
staticフィールドのインライン初期化のみをおこなっている場合、対象の型にbeforefieldinitメタデータフラグが付与される。
一方で明示的なタイプコンストラクタを使用している場合はbeforefieldinitフラグは付与されない。これは、タイプコンストラクタには任意のコードを含めることができ、副作用が発生する可能性もあるため、決められたタイミングで実行しないといけないため。
イベント
- デリゲートで実現されている。
- デリゲートは、タイプセーフなコールバックメソッド
- eventキーワードの指定によって以下の三点が生成される
- イベントの追加/削除はスレッドセーフ。
- ロックにはイベントハンドラオブジェクト自身が利用される
public class Class1 { event EventHandler Event; }
というクラスをILで確認したら、
.class public auto ansi beforefieldinit ConsoleApplication1.Class1 extends [mscorlib]System.Object { .field private class [mscorlib]System.EventHandler Event .method private hidebysig specialname instance void add_Event(class [mscorlib]System.EventHandler 'value') cil managed synchronized { // コード サイズ 24 (0x18) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.0 IL_0002: ldfld class [mscorlib]System.EventHandler ConsoleApplication3.Class1::Event IL_0007: ldarg.1 IL_0008: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate) IL_000d: castclass [mscorlib]System.EventHandler IL_0012: stfld class [mscorlib]System.EventHandler ConsoleApplication3.Class1::Event IL_0017: ret } // end of method Class1::add_Event .method private hidebysig specialname instance void remove_Event(class [mscorlib]System.EventHandler 'value') cil managed synchronized { // コード サイズ 24 (0x18) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.0 IL_0002: ldfld class [mscorlib]System.EventHandler ConsoleApplication3.Class1::Event IL_0007: ldarg.1 IL_0008: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate) IL_000d: castclass [mscorlib]System.EventHandler IL_0012: stfld class [mscorlib]System.EventHandler ConsoleApplication3.Class1::Event IL_0017: ret } // end of method Class1::remove_Event .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // コード サイズ 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Class1::.ctor .event [mscorlib]System.EventHandler Event { .addon instance void ConsoleApplication3.Class1::add_Event(class [mscorlib]System.EventHandler) .removeon instance void ConsoleApplication3.Class1::remove_Event(class [mscorlib]System.EventHandler) } // end of event Class1::Event }
となっていた。