IL C#のルールを超える禁術 ~DynamicMethod~
あいさつ
どうも、はかせです。
前回の記事ではAssemblyBuilderを使って、
動的にdllとexeを生成してみました。
hakase0274.hatenablog.com
今回はDynamicMethodというものを使って
ILを書いてみようと思います。
DynamicMethodとは何ぞや?AssemblyBuilderとの違いは?
DynamicMethodってのはその名の通り
動的にメソッドを作るメソッドです。
「おいおいメソッド作るだけ?」
「AssemblyBuilderならクラスも作れたのに?」
「つまるとこAssemblyBuilderの機能縮小版?」
確かにそう見えます。
おまけにセーブもできないので
DnSpy等でデバッグもできません・・・
(かなりしんどい)
しかし、DynamicMethodでしかできないこともあります。
それはprivateな部分にアクセスできることです。
AssemblyBuilderは本当にVisualStudioなどで
C#を書いて実行したようなものができますが、
制限なども同じようにかかってしまいます。
その制限をすっ飛ばしてやりたい放題できるのが
DynamicMethodです。
(飛び道具大好きな私はめちゃ好きになりそう)
DynamicMethod使ってみる
さてDynamicMethodがどんなものかわかったとこで早速使います。
一発目からC#のルール無視のprivate変数弄りをやります*+。゚・(●`・д・´●)・゚。+*
まずは適当にprivate変数を持つクラスを作ります。
//とりあえずprivate変数持つクラス public class Hoge { private string name; //コンストラクタで初期値受け取っとく public Hoge(string name) { this.name = name; } //確認用 public string GetName() { return name; } }
Hogeクラスのnameを弄ってみます。
static void CreateMethod() { //変数にhogeを格納 var hoge = new Hoge("hoge"); //初期値を確認 Console.WriteLine(hoge.GetName()); //メソッド名、戻り値、引数、その他オプション //Moduleは作ったメソッドが紐づけられる型 //SkipVisibilityはアクセス範囲のチェックを飛ばすかのフラグ(多分) var dynamicMethod = new DynamicMethod("SetName", null, new[] { typeof(Hoge), typeof(string) }, m: typeof(Hoge).Module, skipVisibility: true); //IL手書きはいつもどおり var il = dynamicMethod.GetILGenerator(); //インスタンスメソッドじゃないからarg0から引数 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Stfld, typeof(Hoge).GetField("name", BindingFlags.NonPublic | BindingFlags.Instance)); il.Emit(OpCodes.Ret); //最後はやっぱりCreate var setName = (Action<Hoge, string>)dynamicMethod.CreateDelegate(typeof(Action<Hoge, string>)); //private変数のnameを書き換えてみる setName(hoge, "Fuga"); //結果を確認 Console.WriteLine(hoge.GetName()); }
流れはやっぱりAssemblyBuilderと同じで、
定義→IL手書き→実体化です。保存はできません。
変わったとこはこの辺
//メソッド名、戻り値、引数、その他オプション //Moduleは作ったメソッドが紐づけられる型 //SkipVisibilityはアクセス範囲のチェックを飛ばすかのフラグ(多分) var dynamicMethod = new DynamicMethod("SetName", null, new[] { typeof(Hoge), typeof(string) }, m: typeof(Hoge).Module, skipVisibility: true);
基本的にAssemblyBuilderのDefineMethodと同じなんですが、
ModuleとSkipVisibilityというオプションが追加されています。
Moduleはどのクラスに紐づくかということです。
メソッド単体で存在はできませんからね。
SkipVisibilityはアクセス範囲のチェックを飛ばすかというフラグ(多分)です。
こいつおかげでprivateな部分にも容赦なく入り込んでいけるっぽいです。
ModuleとSkipVisibilityはとりあえず設定しとけってneuecc神が言ってました。
さて本当にprivate変数を弄れるのかな・・・
やべえええええっ!!!private弄れちゃったよ!!
プライバシーなんてこの世に存在しなかった。
あとがき
今回はDynamicMethodでした。
AssemblyBuilderに比べてできることは少ないし、
デバッグもしにくいで良いとこないじゃんって思ってたんですが、
private変数を弄るっていう言語のルールさえ超越する力を持っていました。
もうなんでもありですねw
それでは今回はこの辺でノシ