3

コンパイル時の型のコンテキスト/スコープで動的式(ユーザー提供)を実行したい。以下の例では、コンテキストは任意のコンパイル時タイプのインスタンスです。評価用のスコープを作成するために、利用可能なすべてのプロパティとそのタイプがコンパイル時にわかっているという事実を利用したいと思います。

var engine = IronPython.Hosting.Python.CreateEngine();
var func = engine.CreateScriptSourceFromString("a + b").Compile();
var context = new { a = 1, b = 2 };
var scope = engine.CreateScope((IDynamicMetaObjectProvider)context); // Fails to compile
var result = func.Execute(scope);
context.a = 5;
var result2 = func.Execute(scope);

私が取りたくない解決策は次のとおりです。

  1. コンテキストがDynamicObjectから継承し、GetMemberを上書きするようにします(パフォーマンス上の理由から)
  2. スコープにコンテキストを追加し、式を「context.a + context.b」に変更します(使いやすさの理由から)

確かに、IDynamicMetaObjectProviderを取得するためのメカニズムはすでに存在しますが、それを理解することはできませんでした。

4

1 に答える 1

0

DLR、コンパイル時に定義されたメンバーを動的に呼び出す方法を自動的に認識します。実際、実際に実装したとしてIDynamicMetaObjectProviderも、動的メタ オブジェクトを試す前に、まず静的に定義されたメンバーを探します。

まず、実際に実装されていない場合は、 plain old clr objectto をキャストする必要はありません (キャストすることもできません) 。IDynamicMetaObjectProvider

第二に、オブジェクトのメンバーが表示されないpythonスコープについての混乱は、.を使用しているという事実に起因すると思いますAnonymous Type. internalAnonymous Typesとしてマークされているため、Python スコープにはメンバーを表示する権限がなく、実装されていないと文句を言います。実際に定義されたオブジェクトまたは. 実際には、メンバーを取得するためのクレイジーで素晴らしいパフォーマンスがあります (ただし、設定はしませ) 。ExpandoObjectExpandoObjectsplain old clr objectDLR

次のベンチマークは、ExpandoObject ゲッターが DLR によって呼び出された poco よりも約 43% 高速に実行されることを示しています。

public class Poco{
    public int One {get;set;}
    public string Test {get;set;}
}

void Main()
{
    var iterations =Math.Pow(10,8);

    dynamic expando = new ExpandoObject();
    expando.One =1;
    expando.Test = "Test";
    dynamic poco = new Poco{One =1, Test = "Test"};

    var stopWatch = new Stopwatch();
    stopWatch.Start();
    for(int i=0; i < iterations; i++){
        var test1 = poco.One;
        var test2 = poco.Test;
    }
    stopWatch.Stop();
    var dlrPocoTime = stopWatch.ElapsedMilliseconds;

    stopWatch = new Stopwatch();
    stopWatch.Start();
    for(int i=0; i < iterations; i++){
        var test1 = expando.One;
        var test2 = expando.Test;
    }
    stopWatch.Stop();
    var expandoTime = stopWatch.ElapsedMilliseconds;


    Console.WriteLine((double)dlrPocoTime/expandoTime);

}
于 2012-08-09T13:39:57.957 に答える