我如何使用reflection来调用私有方法?

在我的class级有一组私人的方法,我需要根据input值dynamic调用一个。 调用代码和目标方法都在同一个实例中。 代码如下所示:

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType); dynMethod.Invoke(this, new object[] { methodParams }); 

在这种情况下, GetMethod()不会返回私有方法。 我需要提供什么BindingFlagsGetMethod()以便它可以find私有方法?

只需更改您的代码以使用接受BindingFlags 的GetMethod的重载版本即可 :

 MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, BindingFlags.NonPublic | BindingFlags.Instance); dynMethod.Invoke(this, new object[] { methodParams }); 

这里是BindingFlags枚举文档 。

BindingFlags.NonPublic不会自行返回任何结果。 事实certificate,将其与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); } 

你确定这不能通过inheritance来完成吗? 反思是解决问题时应该考虑的最后一件事情,它使得重构,理解代码,以及自动分析变得更加困难。

看起来你应该只有一个DrawItem1,DrawItem2等类来覆盖你的dynMethod。

微软最近修改了reflectionAPI渲染大部分这些答案已经过时。 以下应该在现代平台(包括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的超类中, Tgenerics必须显式设置为超类的types。

  • 如果方法是asynchronous的,可以使用await (Task) obj.InvokeMethod(…)

你不能只为每个你想绘制的types有不同的Draw方法吗? 然后调用传入types为itemType的对象的重载Draw方法进行绘制。

你的问题并没有说明itemType是否真正指向不同types的对象。

特别是对私人成员的反思是错误的

  • 反思打破了types安全。 你可以尝试调用一个不存在的方法,或者使用错误的参数,或者参数太多,或者不够多,甚至错误的顺序(这是我最喜欢的:))。 顺便返回types也可以改变。
  • 反思很慢。

私有成员reflection破坏封装原则 ,从而暴露您的代码如下:

  • 增加代码的复杂性 ,因为它必须处理类的内部行为。 隐藏的内容应该隐藏起来。
  • 使代码容易中断,因为它会编译,但如果方法更改了名称,将不会运行。
  • 使私人代码易于打破,因为如果它是私人的,它不打算被这样调用。 也许private方法在调用之前需要一些内部状态。

如果我必须这样做呢?

有这样的情况,当你依赖第三方,或者你需要一些没有暴露的API时,你必须做一些反思。 有些人也使用它来testing他们自己拥有的一些类,但是他们不想改变接口来访问内部成员只是为了testing。

如果你这样做,做对了

  • 减轻容易中断:

为了减轻容易中断的问题,最好的办法是通过unit testing中的testing来检测任何潜在的中断,这些中断可以在持续集成构build或者类似的过程中运行。 当然,这意味着你总是使用相同的程序集(包含私有成员)。 如果你使用dynamic加载和reflection,你喜欢玩火,但你总是可以捕捉到可能产生的exception。

  • 缓解反思的缓慢:

在.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); 

查看我的这篇文章,以查看不同方法调用的基准

我认为你可以通过它BindingFlags.NonPublic GetMethod方法。

BindingFlags.NonPublic