使用ImpromptuInterface调用基类的私有成员

本文关键字:成员 基类 ImpromptuInterface 调用 使用 | 更新日期: 2023-09-27 17:50:06

我有一个框架,允许我使用键盘访问项目中对象的状态和方法。它很大程度上依赖于ImpromptuInterface, ImpromptuInterface非常棒、快速、灵活等等。

例如,我用Impromptu.InvokeMember(myObject, methodName, castParameters)调用方法。它对公共和私有成员工作得很好,但是当我试图调用myObject基类的私有成员时,我得到Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'MyType.MyMethod(Something)' is inaccessible due to its protection level

揭示问题的最简单代码:

public class MainClass
{
    public static void Main(string[] args)
    {
        var type = new PublicType();
        var other = new OtherType();
        Console.WriteLine(Impromptu.InvokeMember(other, "Method", 2)); //works
        Console.WriteLine(Impromptu.InvokeMember(type, "Method", 2)); //crash
    }
}
public class PublicType : OtherType
{}
public class OtherType
{
    private bool Method(object a)
    {
        return a != null;
    }
}

我理解为什么有这样一个问题,我可以看到一些可能的解决方案,比如寻找类,方法被定义的地方,并试图将我的对象转换为那个类,但这很麻烦。

是否有简单的解决方案,最好严格基于即兴?

使用ImpromptuInterface调用基类的私有成员

所以它与DLR一起工作的方式是,您为调用提供上下文Type,以便它可以确定哪些方法是可访问的。默认情况下,即兴使用您正在调用的对象的类型,因此它通常适用于大多数私有方法,但显然不适用于基类。

在您的情况下,您需要为即兴创建您自己的上下文,这在文档usagepprivate中提到,它对后期绑定类型和接口一样有效。从文档中也不清楚,但情况是,您可以为上下文传入typeof()对象。在你的例子中,你可以这样写:

var context = InvokeContext.CreateContext;
Console.WriteLine(Impromptu.InvokeMember(context(type, typeof(OtherType)), "Method", 2));

如果你必须在泛型情况下这样做,它不是很漂亮,但你总是可以捕获异常并递归地尝试基类型,对于第一次工作的一般情况,它不应该减慢速度,类层次结构通常不是很深,因为你只是交互式地做一次而不是几千次,它应该是好的。

var context = InvokeContext.CreateContext;
var type = target.GetType()
while(true){
   try{
      Console.WriteLine(Impromptu.InvokeMember(context(target, type), "Method", 2));  
      break;
   }catch(RuntimeBinderException ex){
       type = type.BaseType;
       if(type ==null)
          throw ex;
   }
}