.NET 4.0静态使用动态对象?

时间:2010-05-06 18:51:19

标签: dynamic c#-4.0 dynamic-language-runtime

我在这里问过另一个相关的问题:casting dynamic to static problem

我已经厌倦了.NET中的XML配置文件,并希望用更加理智的格式替换它们。因此,我正在为C#应用程序编写一个配置文件解析器,它将采用自定义配置文件格式,解析它,并创建一个Python源代码字符串,然后我可以在C#中执行并用作static对象(是那是对的 - 我最终想要一个static(不是静态类型动态)对象。

以下是我的配置文件的示例:

// my custom config file format
GlobalName: ExampleApp

Properties
{
    ExternalServiceTimeout: "120"
}

Python 
{
    // this allows for straight python code to be added to handle custom config
    def MyCustomPython:
     return "cool"
}

使用ANTLR我创建了一个将这种格式转换为Python脚本的Lexer / Parser。所以假设我没有那么好,并且可以使用上面的.config并在其上运行我的Lexer / Parser以获取后面的Python脚本(这有额外的好处,为我的配置提供验证工具)。通过在C#中运行生成的脚本

// simplified example of getting the dynamic python object in C#
// (not how I really do it)
ScriptRuntime py = Python.CreateRuntime(); 
dynamic conf = py.UseFile("conftest.py");
dynamic t = conf.GetConfTest("test");

我可以获得具有配置设置的dynamic对象。我现在可以通过在该对象上调用动态方法来获取C#中的配置文件设置:

//C# calling a method on the dynamic python object
var timeout = t.GetProperty("ExternalServiceTimeout");
//the config also allows for straight Python scripting (via the Python block)
var special = t.MyCustonPython();

当然,我这里没有类型安全,也没有智能感知支持。我有一个dynamic表示我的配置文件,但我想要一个静态的。我知道我的Python对象的类型是什么 - 它实际上是在C#类的实例中新建的。但是因为它发生在python中,它的类型不是C#类型,而是dynamic。我想要做的是将对象强制转换回C#类型,我知道对象是

// doesn't work--can't cast a dynamic to a static type (nulls out)
IConfigSettings staticTypeConfig = t as IConfigSettings

有没有办法弄清楚如何将对象强制转换为静态类型?我很怀疑有......我怀疑我采取了另一种方法,我是不完全确定。 我想知道某人是否有更好的方法......

所以这是我目前的策略:因为我知道python对象的类型,我正在创建一个C#包装类:

public class ConfigSettings : IConfigSettings

接受ctor中的dynamic对象:

    public ConfigSettings(dynamic settings)
    {
        this.DynamicProxy = settings;
    }

    public dynamic DynamicProxy
    {
        get;
        private set;
    }

现在我有一个Python动态对象的引用,我知道它的类型。所以我可以把包装器放在我知道的Python方法中:

// wrapper access to the underlying dynamic object
// this makes my dynamic object appear 'static' 
public string GetSetting(string key)
{
    return this.DynamicProxy.GetProperty(key).ToString();
}

现在通过这个静态代理访问动态对象,因此显然可以通过接口等在静态C#世界中传递:

// dependency inject the dynamic object around
IBusinessLogic logic = new BusinessLogic(IConfigSettings config);

这个解决方案具有我们所熟知和喜爱的所有静态打字功能的好处,同时让我可以选择“拯救”动态:

// the DynamicProxy property give direct access to the dynamic object
var result = config.DynamicProxy.MyCustomPython();

但是,伙计,这似乎是错综复杂的方式来获取一个静态类型的对象!由于整个动态/静态交互世界对我来说是新的,我是真的质疑我的解决方案是否是最优的,或者我是否遗漏了一些关于如何弥合这两个宇宙之间的鸿沟的东西(即将动态对象强制转换为已知的静态类型)。

3 个答案:

答案 0 :(得分:0)

如果“IConfigSettings staticTypeConfig = t as IConfigSettings”不起作用,那么你实际上并没有一个实现IConfigSettings的对象。假设您在Python中声明该类,您应该确保在基类列表中包含该接口,例如:

class C(IConfigSettings):
   def SomeIConfigSettingsMember(self): pass

如果这不起作用,那么如果你发布Python代码也可能会有所帮助。

答案 1 :(得分:0)

在此处C# 4.0: casting dynamic to static查看分拆问题,提供了一种方法。

答案 2 :(得分:0)

开源框架impromptu interface允许您声明一个静态c#接口并包装任何动态对象。