为何InvocationExpression的Arguments是Expression而非ParameterExpression?
InvocationExpression.Arguments 和 LambdaExpression.Parameters 根本不是同一概念,类型定义不同是完全符合设计逻辑的,不存在需要“保持一致”的前提。
LambdaExpression.Parameters是lambda定义阶段的形参声明
形参的作用是声明函数的参数占位符,需要存储参数名、参数类型这类参数独有的元数据,这类节点只能是ParameterExpression类型,普通Expression基类没有对应的属性承载这些信息,因此用更具体的ReadOnlyCollection<ParameterExpression>作为属性类型是完全准确的。
比如定义lambda(int x, string y) => x == y.Length时,x和y就是形参,对应两个ParameterExpression节点。InvocationExpression.Arguments是调用表达式传入的实参列表
实参可以是任意合法的表达式节点,根本不局限于ParameterExpression:你可以传常量、算术运算表达式、方法调用返回值、属性访问表达式、其他lambda调用的结果,甚至是另一个嵌套的lambda表达式。如果强行把属性类型定义为ReadOnlyCollection<ParameterExpression>,绝大多数常见的调用场景都无法表示。
举个最基础的例子:Expression<Func<int, int>> doubleIt = x => x * 2; // 调用时传入常量3,对应ConstantExpression类型,不是ParameterExpression var invocation = Expression.Invoke(doubleIt, Expression.Constant(3));上面代码里
invocation.Arguments[0]是ConstantExpression实例,根本不是ParameterExpression,如果属性类型强约束为ParameterExpression,这段合法代码根本无法通过编译。
哪怕你在调用lambda时传入的是某个变量(对应ParameterExpression节点),也只是实参的其中一种可能情况,ReadOnlyCollection<Expression>作为基类集合,才能覆盖所有合法的实参类型,这是类型系统层面的正确设计。
内容的提问来源于stack exchange,提问作者user16276760

