This project has moved. For the latest updates, please go here.

Trying to get ScopeCompile to work with Dictionary of parameters

Oct 7, 2015 at 4:17 PM
Edited Oct 7, 2015 at 4:19 PM
Hi,

For every "formula" identified with an Id i want to have a cached expression so that i can send a dictionary with custom key-value pairs to evaluate.

I'm pretty new to Expression Evaluator and i wonder if someone can help me get started
Tks in advance!
[TestMethod]
public void TestPerformance()
{
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < 10; i++)
    {
        var parameters = new Dictionary<string, double> { { "X", i }, { "Y", 5 } };
        Evaluate(1, parameters);
    }

    sw.Stop();

}

private bool Evaluate(int expressionId, Dictionary<string, double> values)
{
    Func<object, bool> func;
    if (!functionCache.TryGetValue(expressionId, out func))
    {
        //This would be a factory with real functions and diffferent named parameters
        var exp = new CompiledExpression<bool>
        {
            StringToParse = @"scope[""X""] > scope[""Y""]",
            TypeRegistry = new TypeRegistry()
        };
        exp.TypeRegistry.RegisterSymbol("scope", values);
        func = exp.ScopeCompile();
        functionCache.Add(expressionId, func);
    }
    return func(values);
}
Oct 8, 2015 at 10:01 AM
I think i found a way by using the ExpandoObject.
If someone want to help me to improve it please do :)
[TestMethod]
public void TestPerformance()
{
    var parameters = new Dictionary<string, double> {{"ValueToTest", 5}, {"Max", 1000}, {"Min", 0}};
    var result = Evaluate(1, parameters);

    var sw = Stopwatch.StartNew();
    for (int i = 0; i < 100000; i++)
    {
        parameters["ValueToTest"] = i;
        parameters["Max"] = 1000;
        parameters["Min"] = 0;
        result = Evaluate(1, parameters);
    }

    sw.Stop();
    Console.WriteLine(result);
    Console.WriteLine(sw.ElapsedMilliseconds);
    Console.WriteLine(sw.ElapsedTicks);

}

private bool Evaluate(int expressionId, Dictionary<string, double> values)
{
    MyExpression evaluator;
    if (!functionCache.TryGetValue(expressionId, out evaluator))
    {
        evaluator = new MyExpression("ValueToTest >= Min && ValueToTest <= Max",
            new List<string>() { "ValueToTest", "Min", "Max" });

        functionCache.Add(expressionId, evaluator);
    }
    return evaluator.Evaluate(values);
}

public class MyExpression
{
    private readonly dynamic scope;
    private IDictionary<string, object> underlyingObject;
    private readonly Func<bool> func;

    public MyExpression(string expression, IEnumerable<string> parameters)
    {
        scope = new ExpandoObject();
        underlyingObject = scope;
        foreach (var parameter in parameters)
        {
            underlyingObject.Add(parameter, null);
            expression = expression.Replace(parameter, "dynamicScope." + parameter);
        }

        var exp = new CompiledExpression<bool>
        {
            StringToParse = expression,
            TypeRegistry = new TypeRegistry()
        };
        exp.TypeRegistry.RegisterSymbol("dynamicScope", scope);
        func = exp.Compile();

    }

    public bool Evaluate(Dictionary<string, double> values)
    {
        foreach (var kvp in values)
        {
            underlyingObject[kvp.Key] = kvp.Value;
        }
        return func();
    }
}