当前位置:  开发笔记 > 编程语言 > 正文

如何使用反射来调用私有方法?

如何解决《如何使用反射来调用私有方法?》经验,为你挑选了6个好方法。

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

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

在这种情况下,GetMethod()不会返回私有方法.什么BindingFlags我需要提供以GetMethod()使其能找到私有方法?



1> wprl..:

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

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

这是BindingFlags枚举文档.


我会为此烦恼.
@FrankSchwieterman [FTFY](http://stackoverflow.com/a/25415496/1174169)
@MoumitMondal是你的静态方法吗?对于非静态方法,您必须指定`BindingFlags.Instance`以及`BindingFlags.NonPublic`.
添加`BindingFlags.FlattenHierarchy`将使您能够从父类获取方法到您的实例.

2> Jeromy Irvin..:

BindingFlags.NonPublic不会自行返回任何结果.事实证明,结合它可以解决BindingFlags.Instance问题.

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);



3> cod3monk3y..:

如果您真的想让自己陷入困境,可以通过编写扩展方法来更轻松地执行:

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


危险吗?是.但是在我的单元测试命名空间中包装时是一个很棒的帮助扩展.谢谢你.
如果你关心从被调用的方法抛出的真正异常,最好将它包装到try catch块中,并在TargetInvokationException捕获时重新抛出内部异常.我在单元测试助手扩展中这样做.
反射危险吗?嗯... C#,Java,Python ...实际上一切都是危险的,甚至对世界也是如此:D您只需要注意如何安全地进行操作...

4> Owen James..:

Microsoft最近修改了反射API,使得大多数这些答案都过时了.以下内容适用于现代平台(包括Xamarin.Forms和UWP):

obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);

或者作为扩展方法:

public static object InvokeMethod(this T obj, string methodName, params object[] args)
{
    var type = typeof(T);
    var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
    return method.Invoke(obj, args);
}

注意:

如果所需方法在泛型的超类中,objT必须将其显式设置为超类的类型.

如果方法是异步的,您可以使用await (Task) obj.InvokeMethod(…).



5> Bill K..:

你绝对相信这不能通过继承吗?反思是解决问题时应该注意的最后一件事,它会使重构,理解代码以及任何自动分析变得更加困难.

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



6> Fab..:

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

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

反思很慢.

私有成员反射破坏了封装原则,从而将您的代码暴露给以下内容:

增加代码的复杂性,因为它必须处理类的内部行为.隐藏的东西应该隐藏起来.

使代码易于破解,因为它将编译但如果方法更改其名称则不会运行.

使私有代码容易破解,因为如果私有代码是私有的,则不打算以这种方式调用它.也许私有方法在被调用之前需要一些内部状态.

如果我必须这样做怎么办?

有这样的情况,当你依赖第三方或者你需要一些不暴露的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)_method.CreateDelegate(
                 typeof(Func), this);

draw呼叫将比MethodInfo.Invoke 使用draw标准快50倍左右Func:

var res = draw(methodParams);

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


但是,当涉及通常不可单元测试的遗留代码的单元测试时,这是一种绝妙的方法
推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有