我的类中有一组私有方法,我需要根据输入值动态调用一个。调用代码和目标方法都在同一个实例中。代码如下所示:
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
在这种情况下,GetMethod()
将不会返回私有方法。我需要BindingFlags
向GetMethod()
提供什么才能找到私有方法?
答案 0 :(得分:467)
只需更改代码即可使用接受BindingFlags的重载version of GetMethod
:
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });
答案 1 :(得分:65)
BindingFlags.NonPublic
不会自行返回任何结果。事实证明,将其与BindingFlags.Instance
相结合可以解决问题。
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
答案 2 :(得分:50)
如果你真的想要让自己陷入困境,那么通过编写扩展方法让它更容易执行:
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);
}
答案 3 :(得分:14)
Microsoft最近modified the reflection 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(…)
。
答案 4 :(得分:11)
你绝对相信这不能通过继承来完成吗?反思是解决问题时应该注意的最后一件事,它使重构,理解代码以及任何自动分析变得更加困难。
看起来你应该有一个覆盖你的dynMethod的DrawItem1,DrawItem2等类。
答案 5 :(得分:6)
私人成员反思中断encapsulation原则,从而将您的代码暴露给以下内容:
有这样的情况,当你依赖第三方或者你需要一些不暴露的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
快50倍左右
像这样使用draw
作为标准Func
:
var res = draw(methodParams);
检查此post of mine以查看不同方法调用的基准
答案 6 :(得分:2)
您是否可以为要绘制的每种类型设置不同的Draw方法?然后调用重载的Draw方法传入要绘制的itemType类型的对象。
您的问题并不清楚itemType是否真正引用了不同类型的对象。
答案 7 :(得分:1)
我认为你可以传递它BindingFlags.NonPublic
it 是GetMethod
方法。
答案 8 :(得分:1)
尽管对象实例具有保护级别,但仍调用任何方法。享受!
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);
}
答案 9 :(得分:0)
BindingFlags.NonPublic
答案 10 :(得分:0)
阅读这个(补充)答案(有时候是答案)来了解这种情况以及为什么此线程中的某些人抱怨“它仍然无效”
I wrote exactly same code as one of the answers here。但我还有一个问题。我把断点放在
上var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
执行但mi == null
它继续这样的行为,直到我对所涉及的所有项目进行“重建”。我是单元测试一个组件,而反射方法坐在第三个组件中。这完全令人困惑,但我使用立即窗口来发现方法,我发现我尝试单元测试的私有方法有旧名称(我重命名)。这告诉我,即使单元测试项目构建,旧的程序集或PDB仍在那里 - 由于某种原因,项目测试没有建立。 “重建”工作
答案 11 :(得分:0)
应该注意的是,从派生类调用可能会有问题。
容易出错:
this.GetType().GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
正确:
typeof(CurrentClass).GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)