【问题标题】:How to get IDynamicMetaObjectProvider for a static (compile time) type?如何获取静态(编译时)类型的 IDynamicMetaObjectProvider?
【发布时间】:2012-08-03 22:42:30
【问题描述】:

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

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 的机制,但无法弄清楚。

【问题讨论】:

  • 我认为如果有一种方法可以为类生成元对象提供程序,或者有一个 CLR 类型的基本实现提供静态成员,这对于IronPython 范围。对于将新变量添加到范围的情况,它缺少动态扩展机制(类似于 ExpandoObject)。或者这会是您的用例的实际功能吗?
  • 我只执行表达式,所以我不能在范围内分配或添加变量。但是感谢您指出添加会失败。

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


【解决方案1】:

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

首先,如果 plain old clr object 没有实际实现,您不需要(也不能)将其强制转换为 IDynamicMetaObjectProvider

其次,我认为您对 python 范围看不到您的对象成员的困惑是因为您使用的是Anonymous TypeAnonymous Types 被标记为 internal,因此您的 python 作用域无权查看它的成员并抱怨它没有实现它。使用实际定义的对象或ExpandoObjectExpandoObjects 实际上在获取成员方面有非常棒的表现(但没有设置它们),事实上他们在获取成员方面的表现比DLR 访问的plain old clr object 的表现要更好

以下基准测试显示 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);

}

【讨论】:

  • 我知道我不能将 poco 转换为 idmop(编译器告诉我:-),但我的问题是如何为 poco 实现 idmop。示例中只使用了匿名类型。我也可以使用真正的类型。
  • 您是否有一些链接或基准可用于 ExpandoObject 和 poco 之间的性能比较?
  • 您没有实现所有成员在编译时都知道的 IDMOP,DLR 不需要 DynamicMetaObject 来调用非动态成员,它只是这样做。我还添加了一个可以运行的基准。在我的机器上,对 ExpandoObject 上的 getter 的 DLR 调用比对 poco 对象的 DLR 调用快 43%。
猜你喜欢
  • 1970-01-01
  • 2014-09-14
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 2013-08-20
  • 2020-08-22
  • 1970-01-01
相关资源
最近更新 更多