如何获取静态(编译时)类型的IDynamicMetaObjectProvider?

时间:2012-08-06 22:58:50

标签: c#-4.0 ironpython dynamic-language-runtime linq-expressions

我想在编译时类型的上下文/范围内执行动态表达式(由用户提供)。 在下面的示例中,context是任意编译时类型的实例。为了创建评估范围,我想利用所有可用属性及其类型在编译时都已知的事实。

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”(出于可用性原因)
  3. 我敢肯定,已经有了获取IDynamicMetaObjectProvider的机制,但无法弄明白。

1 个答案:

答案 0 :(得分:0)

DLR自动知道如何动态调用在编译时定义的成员。实际上,即使你有IDynamicMetaObjectProvider的实际实现,它也会在查看动态元对象之前先查找静态定义的成员。

首先,如果plain old clr object实际上没有实现它,则您不需要(也不能)IDynamicMetaObjectProvider

其次,我认为你对于没有看到对象成员的python范围的困惑来自你正在使用Anonymous Type的事实。 Anonymous Types被标记为内部,因此您的python范围无权查看其成员并抱怨它没有实现它。使用实际定义的对象或ExpandoObjectExpandoObjects实际上对于获取成员具有疯狂的性能(但不是设置它们),事实上他们更好获得成员性能而不是plain old clr object访问的DLR

以下基准测试显示,ExpandoObject getter的运行速度比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);

}