在我的类中有一组私有方法,我需要根据输入值动态调用其中一个方法。调用代码和目标方法都在同一个实例中。代码如下所示:

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

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


当前回答

微软最近修改了反射API,使大部分答案过时。以下内容应该适用于现代平台(包括Xamarin)。表格及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(…)。

其他回答

微软最近修改了反射API,使大部分答案过时。以下内容应该适用于现代平台(包括Xamarin)。表格及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(…)。

简单地改变你的代码,使用重载版本的GetMethod接受BindingFlags:

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

下面是BindingFlags枚举文档。

你确定这不能通过继承来实现吗?反射是解决问题时最不应该考虑的事情,它会使重构、理解代码和任何自动化分析变得更加困难。

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

调用任何方法,不管它在对象实例上的保护级别。享受吧!

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);
}

阅读这个(补充)答案(有时这是答案)来理解这是怎么回事,以及为什么有些人在这个帖子中抱怨“它仍然不起作用”

我写的代码和这里的一个答案完全一样。但我仍然有一个问题。我设置了断点

var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );

它执行了,但是mi == null

这种情况一直持续到我在所有相关项目上“重新构建”为止。我在单元测试一个程序集,而反射方法位于第三个程序集。这完全令人困惑,但我使用即时窗口来发现方法,我发现我尝试单元测试的私有方法有旧名称(我重新命名了它)。这告诉我,即使单元测试项目构建了,旧的程序集或PDB仍然存在——由于某种原因,它测试的项目没有构建。“重建”工作