もくじ
目次(WPF/xaml/C#/C++関連メモ) - tera1707’s blog
やりたいこと
以前、.NetFrameworkでのUnitTestをつくるときに、privateやinternalなメソッドを外から呼ぶ方法を調べたが、.NET6で同じことをしようとすると、PrivateObject
クラスが使えなくなっていた。
.NET6でもprivateなメソッドをUnitTestしたいので、外から呼ぶやり方を調べたい。
やりかた
リフレクション(Reflection
)を使う。
サンプル(privateなインスタンスメソッド)
具体的には、下記のようなコードを書く。
呼ばれる側dllのコード
namespace ClassLibrary1 { public class MyClass1 { private int MyMethod() => 321; } }
呼ぶ側のコード
// exeを呼び出す var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll"); // exe内のクラスを呼び出す var type = asm2?.GetType("ClassLibrary1.MyClass1"); // そのクラスをインスタンス化する var obj = Activator.CreateInstance(type) as ClassLibrary1.MyClass1; // 名前を指定してメソッドを取得 var method = type.GetMethod("MyMethod", BindingFlags.Instance | BindingFlags.NonPublic); // そのメソッドを、使うインスタンスを指定して実行 var ret3 = method.Invoke(obj, null);
サンプル(privateなstaticメソッド)
GetMethod()
に渡すBindingFlags
のフラグを、BindingFlags.Static
にして、method.Invoke()の第一引数に渡すobjectをnullにしてやると、Staticなメソッドも呼べる。
(BindingFlags.Staticにせずにstaticなメソッドを呼ぶと、GetMethodの戻り値がnullになる。フラグ指定を間違えるとそうなるっぽい)
呼ばれる側
namespace ClassLibrary1 { public class MyClass1 { private static int MyStaticMethod() => 999; } }
呼ぶ側
var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll"); var type = asm2?.GetType("ClassLibrary1.MyClass1"); var method = type.GetMethod("MyStaticMethod", BindingFlags.Static | BindingFlags.NonPublic); var ret3 = method.Invoke(null, null);//objはいらない
同じように、BindingFlags.NonPublic
をBindingFlags.Public
にしてやると、publicなメソッドもこのやり方で呼べる。
サンプル(引数があるメソッド)
引数のあるメソッドを呼ぶためには、method.Invoke()
の第二引数に、呼ぶメソッドに渡す引数を入れてやる。
引数のあるメソッド
namespace ClassLibrary1 { public class MyClass1 { private static int MyStaticMethod(string arg1, int arg2, double[] ds) => 999; } }
呼ぶ方
var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll"); var type = asm2?.GetType("ClassLibrary1.MyClass1"); var method = type.GetMethod("MyStaticMethod", BindingFlags.Static | BindingFlags.NonPublic); double[] ds = new double[] { 1.0, 2.0, 3.0 }; object[] args = { "abc", 1, ds }; var ret3 = method?.Invoke(null, args);
method.Invoke()の第二引数には、
method?.Invoke(null, "abc", 1, ds) ではなく、
先にobject[] objs = { "abc", 1, ds };
としてから
method?.Invoke(null, objs);とする必要がある。