我在这里问了另一个相关的问题:将动态转换为静态问题
我已经厌倦了 .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,我创建了一个 Lexer/Parser,它将这种格式转换为 Python 脚本。所以假设我没有问题,并且可以使用上面的 .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
dynamic
在ctor中接受一个对象:
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();
但是,伙计,这似乎是获取静态类型对象的一种相当复杂的方式!由于整个动态/静态交互世界对我来说是新的,我真的在质疑我的解决方案是否是最佳的,或者我是否遗漏了一些关于如何桥接的东西(即某种将动态对象转换为已知静态类型的方法)这两个宇宙之间的鸿沟。