dynamicexpresso / DynamicExpresso

C# expressions interpreter
http://dynamic-expresso.azurewebsites.net/
MIT License
1.99k stars 374 forks source link

Getting error on IEnumerable Sum() method: "violates the constraint of type 'TAccumulator'." #280

Closed davideicardi closed 1 year ago

davideicardi commented 1 year ago

Discussed in https://github.com/dynamicexpresso/DynamicExpresso/discussions/279

Originally posted by **pburrows** March 19, 2023 I have an expression: ``` Enemies.Sum(p=>p.TotalDollarsEarned) > 50 ``` Where "Enemies" is a parameter of type `List` Defined as: ``` private class ComplexExpressionParameter { public string FirstName { get; set; } public string LastName { get; set; } public decimal TotalDollarsEarned { get; set; } } ``` I am getting the error (I'll paste the full error at the bottom): ``` ---> System.Security.VerificationException: Method System.Linq.Enumerable.Sum: type argument 'System.Object' violates the constraint of type parameter 'TAccumulator'. ``` Is there something I'm missing in getting Sum() to work? It looks like some issue where the variable Enemies is an object and not an IEnumerable, but I'm not sure what to do about that. I already tried casting it as List in my expression and that doesn't work. ---- Full Error: ``` System.ArgumentException: GenericArguments[2], 'System.Object', on 'TResult Sum[TSource,TResult,TAccumulator](System.Collections.Generic.IEnumerable`1[TSource], System.Func`2[TSource,TResult])' violates the constraint of type 'TAccumulator'. ---> System.Security.VerificationException: Method System.Linq.Enumerable.Sum: type argument 'System.Object' violates the constraint of type parameter 'TAccumulator'. at System.RuntimeMethodHandle.GetStubIfNeeded(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[] methodInstantiation) at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation) --- End of inner exception stack trace --- at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e) at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation) at DynamicExpresso.Parsing.Parser.MakeGenericMethod(MethodData method) at DynamicExpresso.Parsing.Parser.CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression[] args) at DynamicExpresso.Parsing.Parser.<>c__DisplayClass110_0.b__0(MethodData m) at System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray() at DynamicExpresso.Parsing.Parser.FindBestMethod(IEnumerable`1 methods, Expression[] args) at DynamicExpresso.Parsing.Parser.FindBestMethod(IEnumerable`1 methods, Expression[] args) at DynamicExpresso.Parsing.Parser.FindExtensionMethods(String methodName, Expression[] args) at DynamicExpresso.Parsing.Parser.ParseExtensionMethodInvocation(Type type, Expression instance, Int32 errorPos, String id, Expression[] args) at DynamicExpresso.Parsing.Parser.ParseMethodInvocation(Type type, Expression instance, Int32 errorPos, String methodName) at DynamicExpresso.Parsing.Parser.ParseMemberAccess(Type type, Expression instance) at DynamicExpresso.Parsing.Parser.ParseMemberAccess(Expression instance) at DynamicExpresso.Parsing.Parser.ParsePrimary() at DynamicExpresso.Parsing.Parser.ParseUnary() at DynamicExpresso.Parsing.Parser.ParseMultiplicative() at DynamicExpresso.Parsing.Parser.ParseAdditive() at DynamicExpresso.Parsing.Parser.ParseShift() at DynamicExpresso.Parsing.Parser.ParseTypeTesting() at DynamicExpresso.Parsing.Parser.ParseComparison() at DynamicExpresso.Parsing.Parser.ParseLogicalAnd() at DynamicExpresso.Parsing.Parser.ParseLogicalXor() at DynamicExpresso.Parsing.Parser.ParseLogicalOr() at DynamicExpresso.Parsing.Parser.ParseConditionalAnd() at DynamicExpresso.Parsing.Parser.ParseConditionalOr() at DynamicExpresso.Parsing.Parser.ParseConditional() at DynamicExpresso.Parsing.Parser.ParseAssignment() at DynamicExpresso.Parsing.Parser.ParseExpressionSegment() at DynamicExpresso.Parsing.Parser.ParseExpressionSegment(Type returnType) at DynamicExpresso.Parsing.Parser.Parse() at DynamicExpresso.Parsing.Parser.Parse(ParserArguments arguments) at DynamicExpresso.Interpreter.ParseAsLambda(String expressionText, Type expressionType, Parameter[] parameters) at DynamicExpresso.Interpreter.Parse(String expressionText, Type expressionType, Parameter[] parameters) at DynamicExpresso.Interpreter.Parse(String expressionText, Parameter[] parameters) at Commissions.Api.CommissionPlans.Engine.ExpressionEngines.DynamicExpresso.DynamicExpressoHelpers.GetLambdaFromExpression(String expression, Parameter[] parameters, Boolean cache) in ... ```
metoule commented 1 year ago

I confirm it's a duplicate of #270 and that it was fixed via #274.

The following test works on the master branch (and fails when #274 is reverted):

private class ComplexExpressionParameter
{
  public decimal TotalDollarsEarned { get; set; }
}

[Test]
public void GitHub_Issue_280()
{
  var interpreter = new Interpreter(InterpreterOptions.Default | InterpreterOptions.LambdaExpressions);
  interpreter.SetVariable("Enemies", new List<ComplexExpressionParameter>
  {
    new ComplexExpressionParameter() { TotalDollarsEarned = 22 },
    new ComplexExpressionParameter() { TotalDollarsEarned = 23 },
  });

  var result = interpreter.Eval<decimal>("Enemies.Sum(p => p.TotalDollarsEarned)");
  Assert.AreEqual(45, result);
}

@davideicardi maybe you can release a new version?

davideicardi commented 1 year ago

Close this because already fixed in v2.16.0. Thank you @metoule !