I’ve been working on a prototype of a Dynamic Pipeline for MetaSharp using the new Linq Expressions in .NET 4. I’m pretty darn excited about it, here is what I have working so far:
[Test] public void BinaryVariablesTest() { var result = this.pipeline.Eval<int>("x * y", new { x = 3, y = 7 }); Assert.AreEqual(21, result); }
What I’m doing here is compiling the string as MetaSharp code then using a node visitor to generate the appropriate linq expressions. The trick here is the context parameter being passed in. This object contains all of the properties and methods allowed to be called from the expression, essentially it’s the “this” parameter. To get this to work you can use the handy dandy ConstantExpression. Here is how I’m doing it:
public class ReferenceExpressionVisitor : TransformVisitor<linq.Expression, ReferenceExpression> { protected override IEnumerable<linq.Expression> Visit( IEnumerable<linq.Expression> items, ReferenceExpression visitedObject) { IDynamicContextService parameterService = this.ServiceProvider.Locate<IDynamicContextService>(); yield return linq.Expression.PropertyOrField( linq.Expression.Constant(parameterService.Context), visitedObject.Name); } }
The constant allows us to call properties or fields on the context object directly. You should even be able to attach lambda expressions to fields so you can call those as well. I have to do some restructuring in order to enable everything like Method calls and whatnot but it should all be doable. Very sweet. Also the dynamic pipeline will have to have some type of caching provider, clearly you wouldn’t want to rebuild these expressions every single time you try to execute it. Optionally I could just give back a delegate instead of executing it directly, then let the caller do all the caching. That sounds easier and more flexible actually now that I think about it.
What’s cool about this though isn’t the fact that you can compile expressions dynamically (which is pretty cool but there are others out there already) but the fact that you will be able to dynamically compile DSLs… which reduce to dynamic expressions. Imagine this:
when truck is late: apply discount(.1); when truck is early: apply bonus(.1); when truck cost > $10,000: notify
You compile your DSL into MetaSharp nodes, transform it into Common language nodes then transform that into dynamic linq expressions. Very sweet! You might transform this into something like:
if(truck.late) { context.discount(.1); } if(truck.early) { context.bonus(.1); } if(truck.cost > 10000) { context.notify(); }
Where you’d have a custom ShippingContext object with all of the methods and properties you wanted to expose in your DSL. This would be really handy for creating all sorts of systems that have the potential to have rapidly changing rules and also, potentially, enable business analysts to author their own rules.