3

我继承了一种小型脚本语言,我正在尝试将其移植到 DLR,以便更易于管理。到目前为止,它已经相当直截了当。尽管尝试动态调用变量的成员,但我遇到了问题。当前的语言在 .NET 上运行并使用解析循环和反射来执行此操作,但我希望能够摆脱这种情况。以下是脚本语言的示例:

string $system1RemoteUri;
string $dbconnection = $config.GetDBConnection ("somedb");
float $minBad = 0.998;
float $minGood = 0.2;

$systen1RemoteURI、$minBad 和 $minGood 是与 $dbconnection 一起在脚本中设置的变量。但是 $dbconnection 将从传入的名为 $config 的变量中获取其值。这 4 个变量需要对调用者可用,因此它们被传递到 lambda,最初为 null。这是生成的 Lambda IL(调试视图):

.Lambda #Lambda1<Delegate6$1>(
    System.String& $$system1RemoteUri,
    System.String& $$dbconnection,
    System.Double& $$minBad,
    System.Double& $$minGood
    System.Object $$config) {
    .Block() {
        $$minBad = 0.998D;
        $$minGood = 0.2D
    }

    //Some assignment similar to...
    //.Dynamic Call GetDBConnection($config, "somedb");
}

我想弄清楚的是如何使用 Expression.Dynamic 发出 $config.GetDBConnection("somedb")。通过查看 Sympl 库中的示例,我相信发出的 IL 应该如下所示:.Dynamic Call GetdbConnection($config, "somedb") 但我无法弄清楚如何从 Expression.Dynamic 中实际发出它。

它似乎想要一个我无法正确创建的 CallSiteBinder,而且我不明白 Expression.Dynamic 的参数顺序是什么,因为它似乎只想要调用“成员”,而不是基础。

我不知道 $config 的运行时类型,它只是一个实现名为 GetDBConnection(string) 的函数的对象。这不是由接口或基类提供的。

任何帮助,将不胜感激。

4

1 回答 1

4

您可以将其转换为 InvokeMemberBinder 或将“$config.GetDBConnection”转换为 GetMember,然后对传递 $someDb 作为参数的结果执行 Invoke。

要实现 GetMemberBinder 和 InvokeMemberBinder,您可以使用 DLR 外层 DefaultBinder 类。在最新的 IronPython/IronRuby 源代码中,您可以凭空创建一个新的 DefaultBinder 实例。然后在您的 FallbackGetMember / FallbackInvoke 中,您可以调用 defaultBinder.GetMember(...) 和 defaultBinder.Call(应重命名为 Invoke)。这将为您处理大多数 .NET 类型。所有实现 IDynamicMetaObjectProvider 的对象也可以使用它。对于其他动态操作,您可以在默认活页夹上使用其他方法。如果你想开始自定义你的重载分辨率和绑定规则,它有很多你可以转动的旋钮。

不幸的是,默认绑定器现在没有 InvokeMemberBinder 实现,因此您可能最好使用 GetMember/Invoke。

于 2010-01-26T07:10:08.033 回答