sklose/NCalc2

BigInteger context functions not working

Opened this issue · 2 comments

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());
}

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.

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