Closed airs1991 closed 1 year ago
Can you please paste the entire code sample? I suspect we only support Func
lambdas, but not Action
lambdas (ie those with no return type).
@airs1991
Maybe the problem is that DS try to call the standard .All
function instead of your custom one?
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all?view=net-7.0
Can you try to use a different name? But yes, having the full code can help us to understand better the problem. If you can I suggest to write it as other unit test...
@davideicardi You're right, indeed the All
name affects parsing.
But when I try to resolve with a custom name, I get a new error:
Here is my test code.
public static class Extend
{
public static void ActionToAll<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
}
public void TestForeach()
{
DynamicExpresso.Interpreter interpreter = new(DynamicExpresso.InterpreterOptions.LambdaExpressions);
List<Npc> testnpcs = new();
for (int i = 0; i < 5; i++)
testnpcs.Add(new Npc { money = 0 });
interpreter.Reference(typeof(Extend));
interpreter.SetVariable("NearNpcs", testnpcs);
var func = interpreter.ParseAsDelegate<Action>("NearNpcs.ActionToAll(n=>n.money=10)");
func.Invoke();
}
E 0:00:03:0634 :0 @ System.Linq.Expressions.Expression DynamicExpresso.Parsing.Parser.ParseMethodInvocation(System.Type , System.Linq.Expressions.Expression , Int32 , System.String , DynamicExpresso.Parsing.TokenId , System.String , DynamicExpresso.Parsing.TokenId , System.String ): DynamicExpresso.Exceptions.NoApplicableMethodException: No applicable method 'ActionToAll' exists in type 'List`1' (at index 8).
I tried changing the extension method from IEnumerable to List:
public static class Extend
{
public static void ActionToAll<T>(this List<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
}
But still the same. I don't understand why
interpreter.Reference(typeof(Extend))
doesn't work.
Yes, that's the issue I suspect: we probably find the ActionToAll
method, but can't use it because the lambda parser expects the lambda to have a return value. I'll have a look, thanks for posting the code!
I've reproduced with a simpler example that doesn't require registering the extension method (using List.ForEach
):
private class Npc
{
public int Money { get; set; }
}
[Test]
public void Lambda_ShouldAllowActionLambda()
{
var target = new Interpreter(InterpreterOptions.Default | InterpreterOptions.LambdaExpressions);
target.EnableAssignment(AssignmentOperators.All);
var list = new List<Npc>() { new Npc { Money = 10 } };
target.SetVariable("list", list);
var result = target.Eval(@"list.ForEach(n => n.Money = 5)");
Assert.IsNull(result);
Assert.AreEqual(5, list[0].Money);
}
Exception:
DynamicExpresso.Exceptions.NoApplicableMethodException : No applicable method 'ForEach' exists in type 'List`1' (at index 5).
To implement the mocked foreach, I use an extension method:
I want to change the money field of each npc in
List<Npc> NearNpcs
to 10, so I wrote a Lambda string:"NearNpcs.All(n=>n.money=10)"
(The
InterpreterOptions.LambdaExpressions
setting is already turned on, and theExtend
class and associated required variables are registered.)It reported the error:
Does Lambda parsing currently only support conditional parsing that can return bool?