Using IN with a parameter rather than a list

Aug 8, 2010 at 9:04 PM

I have a function

in(MyCountry, 'IE','UK','DE','ES')

which works fine.

However if I replace the country list with a variable, e.g.

in(MyCountry, CountryList)

and use the code

Expression ex = new Expression("in(MyCountry, CountryList)", EvaluateOptions.IgnoreCase | EvaluateOptions.NoCache);

ex.EvaluateParameter += delegate(String name, NCalc.ParameterArgs arg) { arg.Result = GetValue(name); };

and GetValue("CountryList") returns 'IE','UK','DE','ES' then it does not work

Any ideas?

 

Aug 14, 2010 at 9:58 PM

Here's the code:

        private void EvaluateArgument(String name, NCalc.ParameterArgs arg)
        {
            if(name == "EU")
                arg.Result = "1,2,3,4";
        }
        public object Evaluate(string expression)
        {
            Expression ex = new Expression(expression, EvaluateOptions.IgnoreCase | EvaluateOptions.NoCache);
            ex.EvaluateParameter += EvaluateArgument;
            return ex.Evaluate();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            tbRes.Text = Evaluate("in(1,EU)").ToString();
        }

Aug 15, 2010 at 1:39 PM

Hey,

the problem relates to the way that "1,2,3,4" is treated as a string and not an array within NCalc.

I don't think that arrays are something NCalcs supports. (i dont see it in the grammar)

this together with the equality comparision used within the "in" function mean that "1"!="1,2,3,4"

the solution is either to get NCalc to support arrays (means regenerating the grammar and changing some inner workings) or to change how the in function works:

if you search the codebase for " #region In"

then change this:  ( note that we can't just use .Contains here as we do not know the type of either argument)

// Goes through any values, and stop when one is found
            for (int i = 1; i < function.Expressions.Length; i++) {
                object argument = evaluator.Evaluate(function.Expressions[i]);
                if (evaluator.CompareUsingMostPreciseType(parameter, argument) == 0) {
                    evaluation = true;
                    break;
                }
            }

to this (you might need to reference system.linq)

// Goes through any values, and stop when one is found
            for (int i = 1; i < function.Expressions.Length; i++) {
                object argument = evaluator.Evaluate(function.Expressions[i]);
                string stringargument = argument as string;
                if (stringargument !=  null) {
                    if (stringargument.Split(new[] {','}).Any(arg => evaluator.CompareUsingMostPreciseType(parameter, arg) == 0)) {
                        evaluation = true;
                        break;
                    }                
                } else if (evaluator.CompareUsingMostPreciseType(parameter, argument) == 0) {
                    evaluation = true;
                    break;
                }
            }

you will get the answer you expect.  Note that this doesn't currently allow you to emply expressions within the string you pass eg "1+1,2+3,4,5" but it'd not be hard to add.

David