OITA: Oika's Information Technological Activities

@oika 情報技術的活動日誌。

C# 非公開メンバへアクセスするためのReflectionラッパーライブラリ「Merror」公開

privateなフィールドの値を外からいじったり、
protectedメソッドを外から使ったり、
privateコンストラクタしか持ってないクラスのインスタンスを作ったり、
そういう掟破りなことをするReflectionのメソッド群を
いくらか直感的に使うためのラッパを作りました。

ソース公開だよ。

https://github.com/oika/Merror
ソース内のコメント等全日本語w

お恥ずかしながら未だgitすら使い慣れてないので
githubってのは全然使い方がよくわからんね。
NuGetでの公開方法とかもそのうち勉強しときます。

ちょうどこの前「入れ子になった内部クラスの型をリフレクションで参照する」って話で
リフレクションの例を挙げたのでそれを使おう。

internalなクラスのインスタンスを作って
プライベートフィールドの値を取得する場合、
通常は↓こんなふうにやる。前回と同じコード。

//公開クラスからアセンブリを特定  
var libAssembly = Assembly.GetAssembly(typeof(OfficeHoge.TeamA.LibA.PublicClass));  
   
//クラス型を取得  
var typePerson = libAssembly.GetType("OfficeHoge.TeamA.LibA.HiddenPerson");  
   
//コンストラクタからインスタンス生成  
var person = typePerson.GetConstructor(new[] { typeof(string) })  
                       .Invoke(new object[] { "一郎" });  
   
//firstNameフィールドの値を取得  
var fldFstName = typePerson.GetField("firstName", BindingFlags.Instance | BindingFlags.NonPublic);  
var fstName = (string)fldFstName.GetValue(person);  
   
Console.WriteLine(fstName); //"一郎"  

これを、↓こんなふうに書けるようになります。

//Reflectorを作る  
var reflector = new Reflector("OfficeHoge.TeamA.LibA.HiddenPerson",  
                              typeof(OfficeHoge.TeamA.LibA.PublicClass));  
//インスタンス生成  
var person = reflector.NewInstance("一郎");  
  
//firstNameフィールドの値を取得  
var fstName = (string)reflector.GetField(person, "firstName");  
  
Console.WriteLine(fstName); //"一郎"  

常に公開メンバも非公開メンバも両方探すようにしてるので、
publicだろうかprivateだろうが区別せず使えます。

あと、パラメータにNullを渡す場合とかは
値から引数型を判別できなくなっちゃうので、
そういうときは型情報をセットで渡すExactメソッドを使う。

var person = reflector.NewInstanceExact(ReflectorParam.New<string>(null));  
  

refとかoutパラメータをとるメソッドも使えます。
ref intの引数をとるDoSomethingRefメソッドなら↓こんな感じ。

var refParam = ReflectorParam.New(0, true);  
reflector.InvokeExact(person, "DoSomethingRef", refParam);  
var val = refParam.Value;  

あとはstaticメンバにもアクセスできたり、インデクサも使えたりする。
それ以上の機能はないです。
もうちょっとジェネリック型の汎用メソッドを増やしてもいいかもだけど。