views:

825

answers:

7

Is it possible to evaluate the following in C# at runtime

I have a class that contains 3 properties (Field,Operator,Value)

 rule.Field;
 rule.Operator;
 rule.Value;

this is my rule class...

Now I have a loop

foreach(item in items)
   {
       // here I want to create a dynamic expression to evaluate at runtime
       // something like
       if (item.[rule.field] [rule.operator] [rule.value])
           { do work }
   }

I just don't know the syntax, or if its possible in C#, I know in JS its possible but thats not a compiled language.

Update

Essentially I want a way to eval(stringCode) or a better more supported way.

+1  A: 

I'm not entirely sure what you are saying. Can you try clarifying it a bit?

Are you wanting to to take a string expression and evaluate it at runtime in C#? If so the answer is no. C# does not support such types of dynamic evaluation.

JaredPar
Yes, thats exactly what I am trying to do.
JL
@JL unfortunately this type of evaluation is not supported in C# (even in 4.0).
JaredPar
how then is it possible to compare using a dynamic operator?
JL
JL: What do you mean by "compare using a dynamic operator"?
Jon Skeet
Hmm first post I saw where Jon Sheet's reply is not the accepted answer :)
Ganesh R.
The answer is doing the question injustice by ignoring both the CodeDOM (http://msdn.microsoft.com/en-us/library/y2k85ax6.aspx) and expression trees (http://stackoverflow.com/questions/238413/lambda-expression-tree-parsing). Richard Hein's and Jon's answer are worth a second look.
Oren Trutner
@Oren, the OP is quite simply asking for a feature that is not there. Expression trees cannot solve the problem of evaluating a raw string. The CodeDOM also provides no help here as it's used to generate a structured set of variables into a raw string.
JaredPar
"Essentially I want a way to eval(stringCode) or a better more supported way"
Oren Trutner
@Oren, still confused. How do you think an expression tree or the CodeDOM (neither of which take a String expression as input) will help this situation.
JaredPar
You can compile arbitrary text (via the compiler available from the CSharp provider implementation) you just need to put some 'template' like code around the text. hacky but it does work. Alternatively you can haed into the realms of the LinqPad implementation... the rough general concept is the same, just depends how well you want to do it vs up front effort...
ShuggyCoUk
I would say that in this Jared you are wrong I'm afraid. IT **is** possible, it is simply _tricky_ depending on how much effort you want to spend vs how complex the support needs to be...
ShuggyCoUk
@ShuggyCoUK, you compile a method to a degree. But to do something as the user is suggesting you would have to pass context values into the method so that the names in the expressions were resolvable by the compiler. In order to know that values and names could be passed to the method you would first need to parse the expression. At that point you're back to step 0, interpreting the expression.
JaredPar
@ShuggyCoUK, I would still certainly argue I am write. There is no support for this in the c# language. Properly implementing a method like this forces you to write a parser of some form. Once you have to parse a C# expression to do an evaluation I don't consider that a supported operation. It's a custom feature you've implemented.
JaredPar
you don't need to implement a parser - MS already have it's the CSharpCodeProvider
ShuggyCoUk
you can in fact provide a method which takes the opcodes defined within Reflection.Emit, generates the relevant DynamicMethod and off you go, all without parsing anything... I'm not saying this is easy (especially since the operator semantics will not match the compilers) and you would have to supply the right operator for the literal type. none the less it would work...
ShuggyCoUk
@ShuggyCoUK, which does no parsing. It returns null for the CreateParser method (as does most providers).
JaredPar
@ShuggyCoUK, no you cannot. The dynamic method will not work unless it has parameters which take the values used within the method. Otherwise how would an expression like "variable1 != variable2" be evaluated? The variables are not resolvable in the dynamic method because they live in the original method. They must be passed as parameters. In order to know what parameters, if any, are needed you must understand something about the expression being generated in the method. The most straight forward way to do this is to parse the expression in some manner.
JaredPar
private Func<T,bool> Make<T>(string name, string op, string value){ var foo = new Microsoft.CSharp.CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters(), new[] { "public class Foo { public static bool Eval("+ typeof(T).FullName +" t) { return t."+ name +" "+ op +" "+ value +"; } }" }).CompiledAssembly.GetType("Foo"); return t => (bool)foo.InvokeMember("Eval",BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod ,null, null, new object[] { t });}
ShuggyCoUk
forgive the hideous formatting but there is a limited Eval which would fulfil his needs - I'll work it into my answer
ShuggyCoUk
you might not be able to *create* a parser by calling CreateParser but you can certainly _cause compilation of code with it_ which is **all the user requires**. The example supplied is essentially a proof of this. It's messy as hell and something I would think twice about (and write an awful lot better if I used it) but it is doable.Any language/platform allowing emission of code, at runtime which may interact with the existing set of state in the application can do this (even if some make it vastly easier than others)
ShuggyCoUk
If what you are arguing is that you cannot emit something which interacts with variables *on the current stack frame* without explictly passing them in then sure, but again this is not required in this case because the stack frame in question is fully known at compile time. Extending the example to include code which grabbed the type of item if unknown at compile time and extracted the fieldtype then added a cast to the body of the Eval code would work just fine, you'd just have to recompile per member type
ShuggyCoUk
@ShuggyCoUK, you're using a function which takes an already parsed expression. I'm discussing how to take a raw expression still in string form. Very different and mine certainly requires parsing.
JaredPar
@ShuggyCoUK, knowing the full stack frame is irrelevant as you cannot access values from a different frame using IL. They must be passed as parameters to the function.
JaredPar
obviously the *context* of the expression is not the same as the context of the where the code to literally be inserted into the fucntion above, I never saw that as remotely a requirement for the purposes of this question though, they made the limitations under which they were requiring it to work very clear.
ShuggyCoUk
And I'm saying that the constraints in the OP make it clear that only one item on the stack is requred, and that it is known in advance. Were this not the case then no, this is no longer possible but the OP didn't ask for arbitrary code they asked for *specific* code.
ShuggyCoUk
@ShuggyCoUK, I disagree that it's clear the OP wanted only a single variable. They provided one example using one variable and said "something like this". That could mean quite a bit.
JaredPar
in fact since c# has introspection for parameters (via System.Reflection.MethodInfo.GetCurrentMethod().GetParameters()), You could actually allow them access to anything in scope with the name as it was in the source at compile time the only bit that would be boiler plate to write at each usage point would be passing in the argument values and dealing with any return value.
ShuggyCoUk
@ShuggyCoUK, This will only work for Parameters. It won't work for locals, captured variables, temporary values, unnamable values and types, etc ...
JaredPar
Then the answer is not "no" it is "yes" but only if you stick with these constraints. the only real constraits are that anywhere you wanted to do this you would need to deal with placing the relevant stack variables into an array/collection in the same order they were defined in the method, that any complex transformational code like yields, lambdas or expressions would not work. That lets you do an *awful lot*.
ShuggyCoUk
@ShuggyCoU, You've added very simplfying constraints to a much broader problem. The OP wanted to know if there is an equivalent to JS's eval method in C#. There is not and adding one which is equivalent requires a tremendous amount of work. Although I've enjoyed this discussion, nothing in it has dissuaded me from my thinking on this issue.
JaredPar
simply inserting something like EvalSimple(MethodInfo.GetCurrentMethod().GetParameters(), new[] {a,b,c}, "code goes here"); would get you access to most stuff, providing a @this variable would make access to non private instance variable possible without too much effort. Yes you will bump up against the edges but it's still a big (sand)box
ShuggyCoUk
You're right in that you will never get a true eval (without rewriting a parser as you say and effectively interpreting everything into reflective access). I just thought there was sufficient wiggle room in the OP's question. It was a fun discussion though, I might see how far I can get just for the fun of it, thanks :)
ShuggyCoUk
+2  A: 

You'd have to either use the CodeDOM libraries or create an Expression tree, compile it, and execute it. I think building up the expression tree is the best option.

Of course you could put in a switch statement on your operator, which is not bad because there is a limited number of operators you could use anyways.

Here's a way to do this with expression trees (written in LINQPad):

void Main()
{   
    var programmers = new List<Programmer>{ 
     new Programmer { Name = "Turing", Number = Math.E}, 
     new Programmer { Name = "Babbage", Number = Math.PI}, 
     new Programmer { Name = "Lovelace", Number = Math.E}};


    var rule0 = new Rule<string>() { Field = "Name", Operator = BinaryExpression.Equal, Value = "Turing" };
    var rule1 = new Rule<double>() { Field = "Number", Operator = BinaryExpression.GreaterThan,  Value = 2.719 };

    var matched0 = RunRule<Programmer, string>(programmers, rule0);
    matched0.Dump();

    var matched1 = RunRule<Programmer, double>(programmers, rule1);
    matched1.Dump();

    var matchedBoth = matched0.Intersect(matched1);
    matchedBoth.Dump();

    var matchedEither = matched0.Union(matched1);
    matchedEither.Dump();
}

public IEnumerable<T> RunRule<T, V>(IEnumerable<T> foos, Rule<V> rule) {

     var fieldParam = Expression.Parameter(typeof(T), "f");
     var fieldProp = Expression.Property (fieldParam, rule.Field);
     var valueParam = Expression.Parameter(typeof(V), "v");

     BinaryExpression binaryExpr = rule.Operator(fieldProp, valueParam);

     var lambda = Expression.Lambda<Func<T, V, bool>>(binaryExpr, fieldParam, valueParam);
     var func = lambda.Compile();

     foreach(var foo in foos) {
      var result = func(foo, rule.Value);
      if(result)
       yield return foo;
     }

}

public class Rule<T> {
    public string Field { get; set; }
    public Func<Expression, Expression, BinaryExpression> Operator { get; set; }
    public T Value { get; set; }
}

public class Programmer {
    public string Name { get; set; }
    public double Number { get; set; }
}
Richard Hein
+6  A: 

No, C# doesn't support anything like this directly.

The closest options are:

  • Create a full valid C# program and dynamically compile it with CSharpCodeProvider.
  • Build an expression tree, compile and execute it
  • Perform the evaluation yourself (this may actually be easiest, depending on your operators etc)
Jon Skeet
A: 

You can retrieve the field by reflection. And then implement the operators as methods and uses reflection or some types of enum-delegate mapping to call the operators. The operators should have at least 2 parameters, the input value and the value you are using to test against with.

gilbertc
+1  A: 

CSharpCodeProvider; switch statements that pick the proper different "operators"; the DLR... they are all ways you could do this; but they seem weird solutions to me.

How about just using delegates?

Assuming your Field and Value are numbers, declare something like this:

delegate bool MyOperationDelegate(decimal left, decimal right);
...
class Rule {
    decimal Field;
    decimal Value;
    MyOperationDelegate Operator;
}

Now you can define your 'rule' as, for example, a bunch of lambdas:

Rule rule1 = new Rule;
rule1.Operation = (decimal l, decimal r) => { return l > r; };
rule1.Field = ...

You can make arrays of rules and apply them whichever way you wish.

IEnumerable<Rule> items = ...;

foreach(item in items)
{
    if (item.Operator(item.Field, item.Value))
    { /* do work */ }
}

If Field and Values are not numbers, or the type depends on the specific rule, you can use object instead of decimal, and with a little bit of casting you can make it all work.

That's not a final design; it's just to give you some ideas (for example, you would likely have the class evaluate the delegate on its own via a Check() method or something).

Euro Micelli
+2  A: 

A better design for you would be for your rule to apply the test itself (or to an arbitrary value)

By doing this with Func instances you will get the most flexibility, like so:

IEnumerable<Func<T,bool> tests; // defined somehow at runtime
foreach (var item in items)
{
    foreach (var test in tests)
    {
       if (test(item))
       { 
           //do work with item 
       }
    }
}

then your specific test would be something like this for strong type checking at compile time:

public Func<T,bool> FooEqualsX<T,V>(V x)
{
    return t => EqualityComparer<V>.Default.Equals(t.Foo, x);
}

For a reflective form

public Func<T,bool> MakeTest<T,V>(string name, string op, V value)
{
    Func<T,V> getter;
    var f = typeof(T).GetField(name);
    if (f != null)   
    {
        if (!typeof(V).IsAssignableFrom(f.FieldType))
            throw new ArgumentException(name +" incompatible with "+ typeof(V));
        getter= x => (V)f.GetValue(x);
    }
    else 
    {
        var p = typeof(T).GetProperty(name);
        if (p == null)   
            throw new ArgumentException("No "+ name +" on "+ typeof(T));
        if (!typeof(V).IsAssignableFrom(p.PropertyType))
            throw new ArgumentException(name +" incompatible with "+ typeof(V));
        getter= x => (V)p.GetValue(x, null);
    }
    switch (op)
    {
        case "==":
            return t => EqualityComparer<V>.Default.Equals(getter(t), value);
        case "!=":
            return t => !EqualityComparer<V>.Default.Equals(getter(t), value);
        case ">":
            return t => Comparer<V>.Default.Compare(getter(t), value) > 0;
        // fill in the banks as you need to
        default:
            throw new ArgumentException("unrecognised operator '"+ op +"'");
    }
}

If you wanted to be really introspective and handle any literal without knowing at compile time you could use the CSharpCodeProvider to compile a function assuming something like:

 public static bool Check(T t)
 {
     // your code inserted here
 }

This is of course a massive security hole so whoever can supply code for this must be fully trusted. Here is a somewhat limited implementation for your specific needs (no sanity checking at all)

private Func<T,bool> Make<T>(string name, string op, string value)
{

    var foo = new Microsoft.CSharp.CSharpCodeProvider()
        .CompileAssemblyFromSource(
            new CompilerParameters(), 
            new[] { "public class Foo { public static bool Eval("+ 
                typeof(T).FullName +" t) { return t."+ 
                name +" "+ op +" "+ value 
                +"; } }" }).CompiledAssembly.GetType("Foo");
    return t => (bool)foo.InvokeMember("Eval",
        BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod ,
        null, null, new object[] { t });
}

// use like so:
var f =  Make<string>("Length", ">", "2");

For this to work with arbitrary types you would have to do a bit more reflection to find the target assembly for the type to reference it in the compiler parameters.

private bool Eval(object item, string name, string op, string value)
{

    var foo = new Microsoft.CSharp.CSharpCodeProvider()
        .CompileAssemblyFromSource(
            new CompilerParameters(), 
            new[] { "public class Foo { public static bool Eval("+ 
                item.GetType().FullName +" t) "+
               "{ return t."+ name +" "+ op +" "+ value +"; } }"   
            }).CompiledAssembly.GetType("Foo");
    return (bool)foo.InvokeMember("Eval",
        BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod ,
        null, null, new object[] { item });
}

All the above code is simply a proof of concept, it lacks sanity checking and has serious performance issues.

If you wanted to be even fancier you could use Reflection.Emit with DynamicMethod instances to do it (using proper operators rather than the default comparer instances) but this would require complex handling for types with overridden operators.

By making your check code highly generic you may include more tests in future as you need to. Essentially isolate the part of your code that cares only about a function from t -> true/false from the code that supplies these functions.

ShuggyCoUk
A: 

While it is true that you probably won't find an elegant way to evaluate full C# code on the fly without the use of dynamically compiling code (which is never pretty), you can almost certainly get your rules evaluated in short order using either the DLR (IronPython, IronRuby, etc) or an expression evaluator library that parses and executes a custom syntax. There is one, Script.NET, that provides a very similar syntax to C#.

Take a look here:Evaluating Expressions a Runtime in .NET(C#)

If you have the time / inclination to learn a little Python, then IronPython and the DLR will solve all your issues: Extending your App with IronPython

Nathan