![](/img/trans.png)
[英]C# How do I invoke a private overloaded method using System.Reflection when number of arguments are equal
[英]How do I use reflection to invoke a private method?
我的類中有一組私有方法,我需要根據輸入值動態調用一個。 調用代碼和目標方法都在同一個實例中。 代碼如下所示:
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
在這種情況下, GetMethod()
不會返回私有方法。 我需要向GetMethod()
提供哪些BindingFlags
以便它可以定位私有方法?
只需更改您的代碼以使用接受 BindingFlags 的GetMethod
重載版本:
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(…)
。
你確定這不能通過繼承來完成嗎? 反射是解決問題時最不應該考慮的事情,它使重構、理解代碼和任何自動分析變得更加困難。
看起來您應該只有一個 DrawItem1、DrawItem2 等覆蓋您的 dynMethod 的類。
私有成員反射破壞了封裝原則,從而將您的代碼暴露給以下內容:
有這樣的情況,當你依賴第三方或者你需要一些沒有暴露的api時,你必須做一些反思。 有些人還使用它來測試他們擁有的一些類,但他們不想更改接口以僅用於測試來訪問內部成員。
為了緩解容易中斷的問題,最好的方法是通過在持續集成構建等中運行的單元測試中進行測試來檢測任何潛在的中斷。 當然,這意味着您始終使用相同的程序集(其中包含私有成員)。 如果您使用動態加載和反射,您喜歡玩火,但您始終可以捕獲調用可能產生的異常。
在 .Net Framework 的最新版本中,CreateDelegate 以 50 倍的因子擊敗 MethodInfo 調用:
// 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
快 50 倍左右,使用draw
作為標准Func
,如下所示:
var res = draw(methodParams);
檢查我的這篇文章以查看不同方法調用的基准
難道您不能為要繪制的每種類型使用不同的 Draw 方法嗎? 然后調用重載的 Draw 方法,傳入要繪制的 itemType 類型的對象。
您的問題沒有說明 itemType 是否真正指的是不同類型的對象。
調用任何方法,盡管它在對象實例上具有保護級別。 享受!
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
,其中它是GetMethod
方法。
閱讀這個(補充)答案(有時就是答案)以了解這是怎么回事以及為什么這個線程中的一些人抱怨“它仍然不起作用”
我寫的代碼與這里的答案之一完全相同。 但我仍然有一個問題。 我把斷點放在
var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
它執行了但是mi == null
它繼續這樣的行為,直到我對所有涉及的項目進行“重新構建”。 我正在對一個程序集進行單元測試,而反射方法則在第三個程序集中。 這完全令人困惑,但我使用 Immediate Window 來發現方法,我發現我嘗試進行單元測試的私有方法具有舊名稱(我重命名了它)。 這告訴我,即使單元測試項目構建,舊的程序集或 PDB 仍然存在 - 由於某種原因,它測試的項目沒有構建。 “重建”工作
應該注意的是,從派生類調用可能會有問題。
容易出錯:
this.GetType().GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
正確的:
typeof(CurrentClass).GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
BindingFlags.NonPublic
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.