.NET 4.0 Dynamic object used statically?
- by Kevin Won
I've gotten quite sick of XML configuration files in .NET and want to replace them with a format that is more sane. Therefore, I'm writing a config file parser for C# applications that will take a custom config file format, parse it, and create a Python source string that I can then execute in C# and use as a static object (yes that's right--I want a static (not the static type dyanamic) object in the end).
Here's an example of what my config file looks like:
// 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"
}
Using ANTLR I've created a Lexer/Parser that will convert this format to a Python script. So assume I have that all right and can take the .config above and run my Lexer/Parser on it to get a Python script out the back (this has the added benefit of giving me a validation tool for my config). By running the resultant script in 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");
I can get a dynamic object that has my configuration settings. I can now get my config file settings in C# by invoking a dynamic method on that object:
//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();
of course, I have no type safety here and no intellisense support. I have a dynamic representation of my config file, but I want a static one. I know what my Python object's type is--it is actually newing up in instance of a C# class. But since it's happening in python, it's type is not the C# type, but dynamic instead. What I want to do is then cast the object back to the C# type that I know the object is:
// doesn't work--can't cast a dynamic to a static type (nulls out)
IConfigSettings staticTypeConfig = t as IConfigSettings
Is there any way to figure out how to cast the object to the static type? I'm rather doubtful that there is... so doubtful that I took another approach of which I'm not entirely sure about. I'm wondering if someone has a better way...
So here's my current tactic: since I know the type of the python object, I am creating a C# wrapper class:
public class ConfigSettings : IConfigSettings
that takes in a dynamic object in the ctor:
public ConfigSettings(dynamic settings)
{
this.DynamicProxy = settings;
}
public dynamic DynamicProxy
{
get;
private set;
}
Now I have a reference to the Python dynamic object of which I know the type. So I can then just put wrappers around the Python methods that I know are there:
// 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();
}
Now the dynamic object is accessed through this static proxy and thus can obviously be passed around in the static C# world via interface, etc:
// dependency inject the dynamic object around
IBusinessLogic logic = new BusinessLogic(IConfigSettings config);
This solution has the benefits of all the static typing stuff we know and love while at the same time giving me the option of 'bailing out' to dynamic too:
// the DynamicProxy property give direct access to the dynamic object
var result = config.DynamicProxy.MyCustomPython();
but, man, this seems rather convoluted way of getting to an object that is a static type in the first place! Since the whole dynamic/static interaction world is new to me, I'm really questioning if my solution is optimal or if I'm missing something (i.e. some way of casting that dynamic object to a known static type) about how to bridge the chasm between these two universes.