4

プロジェクト内のオブジェクトの状態とメソッドにキーボードでアクセスできるフレームワークがあります。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;
    }
}

なぜそのような問題があるのか​​ を理解しており、メソッドが定義されているクラスを探して、オブジェクトをそのクラスにキャストしようとするなど、いくつかの可能な解決策を見ることができますが、それは非常に面倒です.

できれば Impromptu に厳密に基づいた簡単な解決策はありますか?

4

1 に答える 1

2

したがって、DLRで機能する方法は、呼び出しにコンテキストを与えて、Typeアクセス可能なメソッドを判別できるようにすることです。デフォルトでは、impromptuは呼び出しているオブジェクトのタイプを使用するため、通常はほとんどのプライベートメソッドで機能しますが、基本クラスでは機能しません。

あなたの場合、inpromptuの独自のコンテキストを作成する必要があります。これは、ドキュメントUsagePrivateに記載されており、インターフェイスだけでなく遅延バインディングタイプでも機能します。また、ドキュメントからは明らかではありませんが、その場合は、コンテキストのtypeof()オブジェクトを渡すことができます。したがって、あなたの例では、次のことができます。

var context = InvokeContext.CreateContext;

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

一般的なケースでこれを行う必要がある場合、それはきれいではありませんが、いつでも例外をキャッチして、基本タイプを再帰的に試すことができます。これは、最初に動作する一般的なケースでは、速度が低下することはなく、クラスです。階層は一般的にそれほど深くはなく、これを数千回ではなく1回だけインタラクティブに実行しているので、問題ないはずです。

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;
   }
}
于 2012-12-31T17:34:48.730 に答える