IL コンストラクタの次はデストラクタを作ろうとしてハマった話
どういう扱いなんだろう
前回取り扱ったコンストラクタは専用の取得メソッドがあったり、
それ用のクラスがあったり大分特別扱いされていました。
じゃデストラクタはどうなってるんでしょうか?
検索結果0・・・・
デストラクタはどうやら普通のメソッドと同じ扱いのようです。
作ってみる
とりあえずこんな感じのものを目指します。
class TestIL { public TestIL() { Console.WriteLine("コンストラクタよばれたよ"); } ~TestIL() { Console.WriteLine("デストラクタよばれたよ"); } }
コンストラクタは前回やったのと同じ感じなので省略します。
詳しくはこちらをどうぞ
hakase0274.hatenablog.com
じゃデストラクタ作ってきましょう。
扱いが普通のメソッドと同じなら
普段通りやればいいかしら・・・?
var finalize = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual, null, null); var il = finalize.GetILGenerator(); var label = il.DefineLabel(); il.Emit(OpCodes.Ldstr, "デストラクタよばれたよ"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })); il.Emit(OpCodes.Leave_S, label); il.Ldarg(0); il.Emit(OpCodes.Call, typeof(object).GetMethod("Finalize")); il.Emit(OpCodes.Endfinally); il.MarkLabel(label); il.Emit(OpCodes.Ret);
それ実行
ん?objectのデストラクタが取れてない。
名前はFinalizeであってるしなんでだろ・・・?
(ググり中・・・・・)
なにやらGetMethodはBIndingFlagsなるものを指定しないとPublicメンバーのみ探すらしい。
NonPublicってのがあったからそれつけてやってみよう。
えぇ・・・・
NonPublicでもダメって詰んでるじゃないですかー・・
さてはILでデストラクタって扱えない感じですかね?
救世主が現れた
Twitterで以下のサイトを紹介してもらいました。
teratail.com
プログラムで無理やりFinalizeを呼び出してみたらどうなるって感じの内容です。
さてこのサイトで使われているBindingFlagsを指定してやってみます。
il.Emit(OpCodes.Call, typeof(object).GetMethod("Finalize",BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance));
行けた!
ILはどんなの吐かれてるかなwkwk
// TestIL using System; public class TestIL { public TestIL() { //Error decoding local variables: Signature type sequence must have at least one element. Console.WriteLine("コンストラクタよばれたよ"); } ~TestIL() { //Discarded unreachable code: IL_000c //Error decoding local variables: Signature type sequence must have at least one element. Console.WriteLine("デストラクタよばれたよ"); } }
うん、概ね想定通り。
良き良き(^ω^)
あとがき
今回はILでデストラクタを定義してみた話でした。
何やらデストラクタってあのBindingFlagsで
完全一致じゃないと取れないらしいです。
(めんどくさい)
そんな特別な立ち位置ならそれ用のメソッドでも用意してくれればいいのに・・・
こんな感じで
public static MethodInfo GetFinalize<T>() { return typeof(T).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance); }
(ないから今回作ったやつです)
それでは今回はこの辺でノシ