问题
I am implementing a DSL in IronPython.
Suppose I have a value hierachy implemented in C# to be used in iron python:
public abstract Value
{
}
public abstract DoubleValue : Value
{
// Constructors...
public double magnitude;
// Arithmetic operators overloaded...
}
public abstract FractionValue : Value
{
// Constructors....
public int numerator;
public int denominator;
// Arithmetic operators overloaded...
}
Due to the operator overloading in C#, i can do this in Python:
# a, b are of type Value
def Sum(a,b):
return a + b
And everything works fine, the function returns an object of type = Value.
But if i want to use a PythonConstant:
# a is of type Value
def Sum5(a):
return a + 5
you get an error type, because the constant 5 is not of Value type.
One solution would be to overload the + operator to work ints like:
public DoubleValue operator+(DoubleValue, int)
but then you get a huge amount of possible combinations and end up with hundreds of overloads in the Value framework. Anyway you still get this problem:
def ReturnFive():
return 5
In this case the returned value is not of Value type, you should do something like:
def ReturnFive():
return DoubleValue(5.0)
But it is a pretty ugly syntax for my DSL.
What would you recommend?
Thank you very much.
回答1:
This is the major issues with DSELs: they don't always play well with native types. Generally you need to wrap the native types; one option is to introduce a function with a very short name (such as _
) that wraps the passed-in value and triggers the operator overloads.
IronPython only has three number types of interest -- System.Int32 (int), System.Double (float), and System.Numerics.BigInteger (long) -- so there aren't too many cases to take care of.
On the C# side you would have something like:
class Value {
static Value WrapLiteral(object literal) {
if(literal is System.Double) {
return DoubleValue((System.Double)literal);
} // etc ...
}
}
When you create the scope for your user scripts, add that function with the short name:
scope.SetVariable("_", Value.WrapLiteral);
Then from the user side, the users only have to do:
def ReturnFive():
return _(5)
It's still a bit ugly, but not too bad.
来源:https://stackoverflow.com/questions/10857353/ironpython-dsl-casting-constants-to-c-sharp-types