クラスにはプライベートメソッドのグループがあり、入力値に基づいて動的に呼び出す必要があります。呼び出しコードとターゲットメソッドの両方が同じインスタンスにあります。コードは次のようになります。
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
この場合、GetMethod()
はプライベートメソッドを返しません。プライベートメソッドを見つけるためにGetMethod()
に提供する必要があるBindingFlags
は何ですか?
コードを変更して、オーバーロードされた GetMethod
のバージョン を使用して、BindingFlagsを受け入れます。
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });
BindingFlags.NonPublic
は、それ自体では結果を返しません。判明したように、それをBindingFlags.Instance
と組み合わせるとうまくいきません。
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
そして、もしあなたが実際にトラブルに巻き込まれたいなら、拡張メソッドを書くことで実行しやすくします:
static class AccessExtensions
{
public static object call(this object o, string methodName, params object[] args)
{
var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
if (mi != null) {
return mi.Invoke (o, args);
}
return null;
}
}
そして使用法:
class Counter
{
public int count { get; private set; }
void incr(int value) { count += value; }
}
[Test]
public void making_questionable_life_choices()
{
Counter c = new Counter ();
c.call ("incr", 2); // "incr" is private !
c.call ("incr", 3);
Assert.AreEqual (5, c.count);
}
Microsoft リフレクションAPIの変更 これらの回答のほとんどは廃止されました。以下は、最新のプラットフォーム(Xamarin.FormsおよびUWPを含む)で動作するはずです。
obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);
または、拡張方法として:
public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
var type = typeof(T);
var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
return method.Invoke(obj, args);
}
注意:
目的のメソッドがobj
のスーパークラスにある場合は、T
ジェネリックをスーパークラスの型に明示的に設定する必要があります。
メソッドが非同期の場合は、await (Task) obj.InvokeMethod(…)
を使用できます。
これは継承ではできないと確信していますか?リフレクションは、問題を解決するときに最後に確認する必要があるものであり、リファクタリング、コードの理解、および自動化された分析をより困難にします。
DynMethodをオーバーライドするDrawItem1、DrawItem2などのクラスが必要なようです。
プライベートメンバーのリフレクションブレーク カプセル化 原則
サードパーティに依存している場合や、公開されていないAPIが必要な場合は、いくつかの考察を行う必要があります。また、一部のクラスをテストするために使用しますが、テストのためだけに内部メンバーへのアクセスを許可するためにインターフェースを変更したくない場合もあります。
破損しやすい問題を軽減するには、継続的な統合ビルドなどで実行される単体テストでテストすることにより、潜在的な破損を検出することが最善です。もちろん、常に同じアセンブリ(プライベートメンバーを含む)を使用することを意味します。動的なロードとリフレクションを使用する場合、火で遊ぶのが好きですが、呼び出しが生成する例外をいつでもキャッチできます。
.Net Frameworkの最近のバージョンでは、CreateDelegateはMethodInfoの50倍の速度で起動します。
// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
typeof(Func<TInput, TOutput[]>), this);
draw
呼び出しは、MethodInfo.Invoke
が標準のdraw
としてFunc
を使用するよりも約50倍高速になります。
var res = draw(methodParams);
これを確認してください 私のポスト 異なるメソッド呼び出しのベンチマークを見る
描画するタイプごとに異なるDrawメソッドを用意することはできませんか?次に、オーバーロードされたDrawメソッドを呼び出して、描画するitemType型のオブジェクトを渡します。
あなたの質問は、itemTypeが異なるタイプのオブジェクトを本当に参照しているかどうかを明確にしません。
渡すことができると思いますBindingFlags.NonPublic
itはGetMethod
メソッドです。
オブジェクトインスタンスの保護レベルにかかわらず、任意のメソッドを呼び出します。楽しい!
public static object InvokeMethod(object obj, string methodName, params object[] methodParams)
{
var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
MethodInfo method = null;
var type = obj.GetType();
while (method == null && type != null)
{
method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
type = type.BaseType;
}
return method?.Invoke(obj, methodParams);
}
BindingFlags.NonPublic
この(補足)答え(時々答え)を読んで、これがどこに行くのかを理解し、whyこのスレッドの一部の人は「まだ動作していません」
ここに答えの1つとまったく同じコードを書きました 。しかし、まだ問題がありました。ブレークポイントを配置しました
var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
実行されましたが、mi == null
そして、関連するすべてのプロジェクトで「再構築」を行うまで、このような動作を続けました。反射法が3番目のアセンブリにある間、1つのアセンブリを単体テストしていました。それは完全に混乱しましたが、メソッドを発見するためにイミディエイトウィンドウを使用し、ユニットテストしようとしたプライベートメソッドの名前が古いことを発見しました(名前を変更しました)。これは、ユニットテストプロジェクトがビルドされても、古いアセンブリまたはPDBがまだ存在することを私に伝えました-何らかの理由で、テストされたプロジェクトはビルドされませんでした。 「再構築」が機能した