-
-
Notifications
You must be signed in to change notification settings - Fork 231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify error message when using np with instance methods #432
Comments
Hello @zspitz , The v1.2.5 has been released. The expression was only working when the method has some parameters such as: In the newest version, null propagation should also work with a method without parameter like you in case. Let me know if everything is now working as expected. Best Regards, Jon Performance Libraries Runtime Evaluation |
@JonathanMagnan Thank you for the quick turnaround on this. But the issue is not quite resolved. When I use public class Foo {
public Foo Foo1 { get; set; }
public string Baz() => "";
}
var selector = "np(Foo1.Baz().Length)";
var prm = Parameter(typeof(Foo));
var parser = new ExpressionParser(new[] { prm }, selector, new object[] { }, ParsingConfig.Default);
var expr = parser.Parse(null)); what expression is supposed to be generated? I would expect to see the equivalent of the following C#: $var0 != null && $var0.Foo1 != null && $var0.Foo1.Baz() != null ? $var0.Foo1.Baz().Length : null checking for all the parts of the member/method chain. Instead, I see the following: $var0.Foo1.Baz() != null ? $var0.Foo1.Baz().Length : null Anything up the chain from the method call doesn't have a null-test generated. I'm not sure what the right thing to do here. Personally, as I noted above, I think method calls should be left out entirely from the np(Foo1.Baz(Foo1.Foo1.Bar, Foo1.Foo1.Bar).Length) should become the equivalent of (line breaks added for readability): $var0 != null &&
$var0.Foo1 != null &&
$var0.Foo1.Foo1 != null &&
$var0.Foo1.Baz(Foo1.Foo1.Bar, Foo1.Foo1.Bar) != null ?
$var0.Foo1.Baz(Foo1.Foo1.Bar, Foo1.Foo1.Bar).Length :
null |
Hello @zspitz, I see your point. That code Param_0 => IIF((Param_0.Foo1.Baz() != null), Convert(Param_0.Foo1.Baz().Length), null) Which is indeed invalid (I did not test this scenario when implementing the It should be like: Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.Foo1 != null)) AndAlso (Param_0.Foo1.Baz() != null)), Convert(Param_0.Foo1.Baz().Length), null) @JonathanMagnan Shall I take a look at the code and see if this can be changed? |
@StefH It's more than just the methods which are up the member chain. Once (I noted this in my previous comment, but your comment didn't respond to this point. Just making sure you've seen it.) NB. You may be interested in the library I've written, which provides various string representations for expression trees: Console.WriteLine(expr.ToString("C#"));
/*
$var0.Foo1.Baz() != null ? $var0.Foo1.Baz().Length : null
*/
Console.WriteLine(expr.ToString("Textual tree", "C#"));
/*
Conditional (int?)
· Test - NotEqual (bool)
· Left - Call (string) Baz
· Object - MemberAccess (Foo) Foo1
· Expression - Parameter (Foo)
· Right - Constant (object)
· IfTrue - Convert (int?)
· Operand - MemberAccess (int) Length
· Expression - Call (string) Baz
· Object - MemberAccess (Foo) Foo1
· Expression - Parameter (Foo)
· IfFalse - Constant (int?)
*/ |
@StefH , sure you can go ahead and propose a pull |
@zspitz I cannot use ExpressionTreeToString in .NET 4.5.2 test project. However I think I solved the issue, can you take a look at the unit tests here?
|
@StefH The unit tests look excellent, thanks. But what happens if the arguments themselves consist of member/method chains? I realize handling this possibility means increased complexity -- we're no longer talking about a simple chain of members/methods, but rather each method could branch out into its own chain via the arguments. But if you decide not to process method arguments, I think it important that this limitation should be clearly documented. |
Hello @zspitz, Would it be an option to mark this issue as resolved? And that you create a new issue regarding the arguments issue? |
Given the following class:
Dynamic LINQ expands the
np(...)
function:to include a null-checking test on every property/field access in the chain:
However,
np
doesn't work with an instance method call:and fails with System.InvalidOperationException: 'Sequence contains no elements'.
Stack trace
```none at System.Linq.ThrowHelper.ThrowNoElementsException() at System.Linq.Dynamic.Core.Parser.ExpressionHelper.CollectExpressions(Boolean addSelf, Expression sourceExpression) at System.Linq.Dynamic.Core.Parser.ExpressionHelper.TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, Boolean addSelf, Expression& generatedExpression) at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseFunctionNullPropagation() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIdentifier() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimaryStart() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimary() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseUnary() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMultiplicative() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAdditive() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseShiftOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseComparisonOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLogicalAndOrOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIn() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAndOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseOrOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLambdaOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseNullCoalescingOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseConditionalOperator() at System.Linq.Dynamic.Core.Parser.ExpressionParser.Parse(Type resultType, Boolean createParameterCtor) at _DynamicLINQ.Program.Main(String[] args) in C:\Users\Spitz\source\repos\_testReflection\_DynamicLINQ\Program.cs:line 66 ```This is understandable, because the translation would require multiple calls to the method, something which should not be done implicitly:
But the error message doesn't make this clear. Having an error message to the effect that "instance methods cannot be used in an
np
chain" would be better.The text was updated successfully, but these errors were encountered: