Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# parse string to Func<T, bool>

Tags:

c#

I'm trying to parse string to create Func instance.

public class A
{
    public int fieldA { get; private set; }
    public bool fieldB { get; private set; }
    public List<int> fieldC { get; private set; }
}

Check the condition of the instance of A class with :

{
    "Type" : "A"
    "Condition" : "fieldA > 0 && fieldB == true"
}

Of course the format of a string can be modified, for easier parsing.

What I want to create is actually :

Func<A, bool> condition = a => a.fieldA > 0 && a.fieldB == true;

Parsing the condition string would not be very hard, but since there are so many A instances, using reflection whenever checking the condition would not be desirable. What I want to do is "construct" this function from string in advance and cache it somewhere, and call cached function when I want to check the condition.

Could you give my any advices?

like image 960
MyBug18 Avatar asked Mar 28 '26 09:03

MyBug18


1 Answers

Using System.Linq.Dynamic.Core you could do something like:

public bool TestCondition(A obj, string condition)
{
    var expr = DynamicExpressionParser.ParseLambda<A, bool>(ParsingConfig.Default, false, condition, new object[0]);
    var func = expr.Compile();
    return func(obj);
}

And invoke it like:

var testResult = TestCondition(anInstanceOfA, "fieldA > 0 && fieldB == true");

If you want to use local variables in your expression you can do:

public static bool TestCondition(A obj, string condition, IDictionary<string, object> args)
{
    var expr = DynamicExpressionParser.ParseLambda(new ParameterExpression[] { Expression.Parameter(typeof(A)) },
        typeof(bool),
        condition,
        new object[] { args });

    var func = expr.Compile();
    return (bool)func.DynamicInvoke(obj);
}

And invoke it like:

var locals = new Dictionary<string, object>();
locals.Add("myInt", 0);
locals.Add("myBool", true);
var check = TestCondition(obj, "fieldA > myInt && fieldB == myBool", locals);

You can also make the method generic so you can reuse it in other circumstances:

public static TOut TestCondition<TIn, TOut>(TIn obj, string condition, IDictionary<string, object> args)
{
    var expr = DynamicExpressionParser.ParseLambda(new ParameterExpression[] { Expression.Parameter(typeof(TIn)) },
        typeof(TOut),
        condition,
        new object[] { args });

    var func = expr.Compile();
    return (TOut)func.DynamicInvoke(obj);
}

.
.
.
TestCondition<A, bool>(obj, "fieldA > myInt && fieldB == myBool", locals)
like image 57
Matteo Umili Avatar answered Mar 29 '26 21:03

Matteo Umili