5

Is it possible to convert string

"value > 5 && value <= 10" 

to if statement?

if (value > 5 && value <= 10)
{
   //do something
}

I have conditions stored as strings in DB, so it must be a dynamic conversion

  • 3
    no not really. You would have to implement this logic yourself. YOu could do so by usinf string.Split(" "); and get all your bits and pieces from there – Denis Schaf Jul 04 '19 at 13:51
  • 1
    Maybe this helps: https://stackoverflow.com/questions/234217/is-it-possible-to-compile-and-execute-new-code-at-runtime-in-net – MakePeaceGreatAgain Jul 04 '19 at 13:52
  • 1
    Do you really have to store these expressions as strings? I think this is possible with reflection, but inefficient and possibly prone to injection attacks. If the conditions are all `a>b & a<=c`, you can store b and c. Alternatively, you can parse the string yourself (to simplify that, you can change the format to something more machine-readable). – the default. Jul 04 '19 at 13:52
  • 7
    Most of the times, when someone is doing such string magic, there is actually a simpler solution, maybe you could try to explain - how you got that string and why you need this? – Rand Random Jul 04 '19 at 13:53
  • I recieve those conditions as part of business logic. I can convert them to more natural solution and store it in DB as 4 columns, but I just wanted to check if it would be possible to parse it out of the box from string. – Kacper Stachowski Jul 04 '19 at 13:57
  • 1
    How does that part of business logic produce or get them? Can it produce them in a better format (such as the 4 columns you mentioned, although I only see 2 here)? – the default. Jul 04 '19 at 13:58
  • Possible duplicate of [How can I evaluate a C# expression dynamically?](https://stackoverflow.com/questions/53844/how-can-i-evaluate-a-c-sharp-expression-dynamically) – baruchiro Jul 04 '19 at 14:01
  • 2
    I'd lean against evaluation of client derived C# expressions as a matter of security. Ideally you need to parse this into some form of AST that you can convert into an expression or just evaluate with your own code. This way you can restrict the types of operations available. Even better, have the upstream business logic create the AST representation rather than a string. – Oliver Jul 04 '19 at 14:04
  • Thanks for your suggestions, but I don't need another angle on the solution :) Just wanted to know if what I asked is possible or not – Kacper Stachowski Jul 04 '19 at 14:05
  • Is the format of strings always the same? As in: value operator number condition value operator number? – Matt Jul 04 '19 at 14:09
  • [execute c# code at runtime from code file](https://stackoverflow.com/questions/4181668/execute-c-sharp-code-at-runtime-from-code-file) – huMpty duMpty Jul 04 '19 at 15:43

4 Answers4

4

Instead you can treat it as a javascript line and can get this done using Windows Script Engines, provided value is a real value instead of variable name.

 if(ScriptEngine.Eval("jscript", "value > 5 && value <= 10"))
   {
     //Your logic
   }

Or if its a variable then you can build a JS function like below to accomplish this:

using (ScriptEngine engine = new ScriptEngine("jscript"))
{
  string JSfunction =  "MyFunc(value){return " + "value > 5 && value <= 10" + "}";

  ParsedScript parsed = engine.Parse(JSfunction);
  if(parsed.CallMethod("MyFunc", 3))
  {  
   // Your Logic
  }
}
HarryPotter
  • 119
  • 7
2

Use Compute method of System.Data.DataTable:

static class ExpressionHelper
{
    private static readonly DataTable dt = new DataTable();
    private static readonly Dictionary<string, string> expressionCache = new Dictionary<string, string>();
    private static readonly Dictionary<string, object> resultCache = new Dictionary<string, object>();

    // to be amended with necessary transforms
    private static readonly (string old, string @new)[] tokens = new[] { ("&&", "AND"), ("||", "OR") };

    public static T Compute<T>(this string expression, params (string name, object value)[] arguments) =>
        (T)Convert.ChangeType(expression.Transform().GetResult(arguments), typeof(T));

    private static object GetResult(this string expression, params (string name, object value)[] arguments)
    {
        foreach (var arg in arguments)
            expression = expression.Replace(arg.name, arg.value.ToString());

        if (resultCache.TryGetValue(expression, out var result))
            return result;

        return resultCache[expression] = dt.Compute(expression, string.Empty);
    }

    private static string Transform(this string expression)
    {
        if (expressionCache.TryGetValue(expression, out var result))
            return result;

        result = expression;
        foreach (var t in tokens)
            result = result.Replace(t.old, t.@new);

        return expressionCache[expression] = result;
    }
}

Usage

var expr = "value > 5 && value <= 10";
var a1 = expr.Compute<bool>(("value", 5)); // false
var a2 = expr.Compute<bool>(("value", 7)); // true
var a3 = expr.Compute<bool>(("value", 11)); // false
CSDev
  • 3,177
  • 6
  • 19
  • 37
1

You could use Linq.Expression to build up the expression tree, the one you provided:

"value > 5 && value <= 10"

var val = Expression.Parameter(typeof(int), "x");
var body = Expression.And(
     Expression.MakeBinary(ExpressionType.GreaterThan, val, Expression.Constant(5)), 
     Expression.MakeBinary(ExpressionType.LessThanOrEqual, val, Expression.Constant(10)));

var lambda = Expression.Lambda<Func<int, bool>>(exp, val);
bool b = lambda.Compile().Invoke(6); //true
bool b = lambda.Compile().Invoke(11); //false

This is just an example to get some idea, still you need a smart way to parse and build the tree.

Johnny
  • 8,939
  • 2
  • 28
  • 33
0

I am afraid that you will have to create the simple parser for that.

You can try use something like FParsec. This is an F# parser library. I am not aware of such code in C#

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
Assassin
  • 1,296
  • 2
  • 14
  • 17