Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

extension method implementation does not work with parameterized input #23

Open
ibt1haj opened this issue Nov 9, 2023 · 2 comments
Open

Comments

@ibt1haj
Copy link

ibt1haj commented Nov 9, 2023

i have implemented a extension function in ncalc-async like so

public static async Task<object> EvaluateCustomMathFunction(Expression exp)
{
    exp.EvaluateFunctionAsync += NCalcExtensionFunctions;
    var result = await exp.EvaluateAsync();
    return result;
}

private static async Task NCalcExtensionFunctions(string name, FunctionArgs args)
{
    if (name == Constants.Pos)
    {
        var tempResult = await args.Parameters[0].EvaluateAsync();

        if (tempResult is IEnumerable<object> list)
        {
            args.Result = list.Select(x => Convert.ToDouble(x) > 0 ? x : 0);
        }
        else
        {
            var doubleResult = Convert.ToDouble(tempResult);
            args.Result = doubleResult > 0 ? doubleResult : 0;
        }
    }
}

the line

var tempResult = await args.Parameters[0].EvaluateAsync();

always returns zero in case of parameterized input

following is a test case with parameterized input

 [Test]
 public async Task EvaluateCustomMathFunction_WithParameters()
 {
     // Arrange
     var exp = new Expression("Pos(A)", EvaluateOptions.IterateParameters);
     exp.Parameters["A"] = new int[] { 5, 10, -5, 10 };

     // Act
     var result = (IEnumerable) await CustomExpressionEvaluation.EvaluateCustomMathFunction(exp);

     // Assert
     Assert.AreEqual(new int[] { 5, 10, 0, 10 },result);
 }

if the input is a static value then the extension function works correctly

[Test]
public async Task EvaluateCustomMathFunction_PositiveNumber()
{
    // Arrange
    var exp = new Expression("Pos(-5)"); 

    // Act
    var result = await CustomExpressionEvaluation.EvaluateCustomMathFunction(exp);

    // Assert
    Assert.That(result, Is.EqualTo(0)); // The method should return 0 for negative input
}

what am i missing in my implementation of the extension method?
i have also opened a discussion for it on #22

@yallie
Copy link
Member

yallie commented Nov 12, 2023

Hello @ibt1haj,

I never used EvaluateOptions.IterateParameters, and it looks to me that IterateParameters implementation is broken.
But I think it's easy to work around this limitation:

private static async Task NCalcExtensionFunctions(string name, FunctionArgs args)
{
	if (name == "Pos")
	{
		var temp = await args.Parameters[0].EvaluateAsync();
		args.Result = Convert.ToDouble(temp) > 0 ? temp : 0;
	}
}

public static async Task<object[]> EvaluateArray(string expression, Dictionary<string, object> parameters)
{
	var expr = new Expression(expression, EvaluateOptions.None);
	expr.EvaluateFunctionAsync += NCalcExtensionFunctions;

	// convert array parameters to scalar parameters
	var count = parameters.Values.OfType<Array>().Min(p => p.Length);
	var results = new List<object>();
	
	for (var i = 0; i < count; i++)
	{
		// get parameters
		foreach (var pair in parameters)
		{
			expr.Parameters[pair.Key] = ((Array)pair.Value).GetValue(i);
		}
		
		// save results
		results.Add(await expr.EvaluateAsync());
	}
	
	return results.ToArray();
}

@yallie
Copy link
Member

yallie commented Nov 12, 2023

Here is the full sample code: https://dotnetfiddle.net/fToXRw

image

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

No branches or pull requests

2 participants