Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OptionForceIntegerNumbersEvaluationsAsDoubleByDefault leads to not recognising three parameter version of Math.Round #112

Open
midgleyc opened this issue Aug 3, 2021 · 2 comments
Assignees

Comments

@midgleyc
Copy link

midgleyc commented Aug 3, 2021

The code

var evaluator = new ExpressionEvaluator()
{
    OptionForceIntegerNumbersEvaluationsAsDoubleByDefault = true
};

string expression = "Math.Round(1,0,MidpointRounding.AwayFromZero)";

Console.WriteLine(expression);
Console.WriteLine(evaluator.Evaluate(expression));

gives the error

[System.Math] object has no Method named "Round".

instead of the expected result "1".

This came about in 1.4.31.0 and worked in 1.4.30.0 (but 1.4.31.0 is a good fix for #110, so thanks for that!)

@codingseb codingseb self-assigned this Aug 4, 2021
@codingseb
Copy link
Owner

codingseb commented Aug 4, 2021

Yes of course as in C# You can't put a double as second argument in Math.Round(double,int,MidpointRounding).
And when you set OptionForceIntegerNumbersEvaluationsAsDoubleByDefault = true it's what you are doing so it's like Math.Round(1d,0d,MidpointRounding.AwayFromZero). This is not possible in C#.
The bug in version 1.4.30.0 is that it forced a conversion of numbers where C# do not. And so it selected sometime wrong methods because of conversions that shouldn't append automatically. So I think current version is more accurate as it is more C# like. I am sorry but there is no way to manage all these cases directly in the code of EE without breaking something or creating very specific conditions that should not be in the code of EE but customized by the user.

So for your case there are 5 solutions to manage it.

  1. You can use the build in and shorter version of Round (without Math, description here) it still make the conversion for you.
Round(1,0,MidpointRounding.AwayFromZero)
  1. You can cast back the second parameter to int
Math.Round(1,(int)0,MidpointRounding.AwayFromZero)
  1. You can manage the call of Math.Round in the event:
evaluator.PreEvaluateFunction+= PreEvaluateFunction;
private void PreEvaluateFunction(object sender, FunctionEvaluationEventArg e)
{
     if(e.Name.Equals("Round") && e.This is ClassOrEnumType classOrTypeName && classOrTypeName.Type == typeof(Math))
     // use e.EvaluateArgs() that you can cast and use how you want.
     // and return the result in e.Value
}
  1. You can specify yourself how you want to cast parameters in specific case with the event : (There is no documentation for this one yet, just a talk in an other issue that I didn't found again. but everything is manageable with the e argument)
evaluator.EvaluateParameterCast += EvaluateParameterCast;
  1. You keep : OptionForceIntegerNumbersEvaluationsAsDoubleByDefault = false and use the C# writing:
Math.Round(1d,0,MidpointRounding.AwayFromZero)

@codingseb codingseb reopened this Aug 4, 2021
@midgleyc
Copy link
Author

midgleyc commented Aug 5, 2021

Thanks, it works well with:

evaluator.EvaluateParameterCast += Evaluator_EvaluateParameterCast;

[...]

private static void Evaluator_EvaluateParameterCast(object? sender, ParameterCastEvaluationEventArg e)
{
    if (e.MethodInfo.DeclaringType == typeof(Math) && e.MethodInfo.Name == "Round" && e.ParameterType == typeof(int) && e.OriginalArg is double original)
    {
        e.Argument = (int) original;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants