sklose / NCalc2

expression evaluator for .NET with built-in compiler
MIT License
162 stars 56 forks source link

BigInteger context functions not working #37

Open mikkleini opened 4 years ago

mikkleini commented 4 years ago

This piece of code throws System.MissingMethodException: 'method not found: Abs'

public class ExpressionContext
{
    public BigInteger Abs(BigInteger x)
    {
        return BigInteger.Abs(x);
    }
}

private static void Test()
{
    Expression expression = new Expression("Abs(-1)");
    var func = expression.ToLambda<ExpressionContext, BigInteger>();
    Console.WriteLine(func(new ExpressionContext()).ToString());
}
fadulalla commented 4 years ago

Method discovery is based on explicit argument type, it doesn't support implicit conversion. -1 is an int so it won't find the method, as it's declared to take BigInteger.

As a workaround, you can do the following:

public class ExpressionContext
{
    public BigInteger MakeBigInteger(int x)
    {
        return new BigInteger(x);
    }
    public BigInteger Abs(BigInteger x)
    {
        return BigInteger.Abs(x);
    }
}

private static void Test()
{
    Expression expression = new Expression("Abs(MakeBigInteger(-1))");
    var func = expression.ToLambda<ExpressionContext, BigInteger>();
    Console.WriteLine(func(new ExpressionContext()).ToString());
}

I know this doesn't exactly solve the problem (i.e. if you're trying to input a big integer, such as MakeBigInteger(1,000,000,000,000,000) then this obviously won't work), but for simple cases it does the job.

Edit: This also applies to other types that support implicit conversion. That is, if you have a Abs(double) method, and call it with an int Abs(1), you'll get "method not found," and you'd have to do Abs(1.0), or create an overload of Abs that takes integers.

eugenca commented 4 months ago

I think BigInteger input could be achieved by something like Expression expression = new Expression("Abs(MakeBigInteger('1,000,000,000,000,000'))"); via string, not integer