Replies: 3 comments 4 replies
-
The restriction exists because optional parameters didn't exist when expression trees were created, and the team has steadfastly refused to expand their support (short of a hypothetical "Expressions2"). IMHO, optional parameters could be supported without breakage by lowering them the same way the compiler does: including the implicit parameter at the call site. The expression consumer would see nothing different than if the user manually wrote the |
Beta Was this translation helpful? Give feedback.
-
Named parameters out of order would require local variables, to preserve the lexical order of side effects in argument expressions. This is likely to result in expression-tree nodes that are not supported by the libraries that receive the trees. To mitigate this, there C# compiler could report a warning when the resulting tree contains such nodes that were never emitted in lower language versions. The developer could then disable this warning if they know that the nodes are supported. using System;
using System.Linq.Expressions;
public class C1 {
private int _counter;
public static int Sum(int a, int b) => a + b;
public int Increment() => _counter++;
public int Decrement() => _counter--;
}
public static class UsingLambdaExpression {
public static Expression<Func<C1, int>> MakeExprInOrder() {
return (C1 c1) => C1.Sum(c1.Increment(), c1.Decrement());
}
public static Expression<Func<C1, int>> MakeExprOutOfOrder() {
return (C1 c1) => C1.Sum(b: c1.Increment(), a: c1.Decrement());
}
}
public static class UsingExpressionTreeApi {
public static Expression<Func<C1, int>> MakeExprInOrder() {
ParameterExpression c1 = Expression.Parameter(typeof(C1), "c1");
return Expression.Lambda<Func<C1, int>>(
Expression.Call(
typeof(C1).GetMethod("Sum")!,
Expression.Call(
c1,
typeof(C1).GetMethod("Increment")!),
Expression.Call(
c1,
typeof(C1).GetMethod("Decrement")!)),
c1);
}
public static Expression<Func<C1, int>> MakeExprOutOfOrder() {
ParameterExpression c1 = Expression.Parameter(typeof(C1), "c1");
ParameterExpression b = Expression.Variable(typeof(C1));
return Expression.Lambda<Func<C1, int>>(
Expression.Block(
typeof(int),
variables: [ b ],
Expression.Assign(b, Expression.Call(
c1,
typeof(C1).GetMethod("Increment")!)),
Expression.Call(
typeof(C1).GetMethod("Sum")!,
Expression.Call(
c1,
typeof(C1).GetMethod("Decrement")!)),
b),
c1);
}
} |
Beta Was this translation helpful? Give feedback.
-
Champion issue: #9246
Summary
Support optional and named arguments in method calls in
Expression
treesMotivation
Errors are reported for calls in
Expression
trees when the call is missing an argument for an optional parameter, or when arguments are named.This results in unnecessary code and differences for expressions within
Expression
trees. And lack of support for optional arguments can lead to breaking changes when a new overload with an optional parameter is applicable at an existing call site.The compiler restrictions should be removed if not needed.
For example, compiling the following with the .NET 10 preview SDK results in errors currently.
Detailed design
Remove the error reporting for these cases in
Expression
trees, and allow the existing method call rewriting to handle optional and named arguments.Drawbacks
Alternatives
Unresolved questions
It's unclear why the restrictions were added originally. An initial investigation hasn't revealed an issue supporting these cases.
Design meetings
Based on a suggestion from @roji to support optional parameters.
Beta Was this translation helpful? Give feedback.
All reactions