我正要以Expression.Lambda编程方式绑定(因为未知/可变类型参数),发现如果目标方法使用params,反射调用与直接调用有点不同。
首先,在官方文档中,“签名”(虽然这更像是 XML-doc):
public static
System.Linq.Expressions.Expression<TDelegate>
Lambda<TDelegate>(
System.Linq.Expressions.Expression body,
params System.Linq.Expressions.ParameterExpression[]? parameters
);
请注意,第二个参数被标记为可选,我们可以写Expression.Lambda<T>(...). 如果在 Visual Studio 中,你转到反汇编的声明列表,你可以看到:
public static
Expression<TDelegate>
Lambda<TDelegate>(
Expression body,
params ParameterExpression[] parameters
);
第二个参数不再标记为选项。现在,当我尝试使用反射调用此方法时:
var lambdaFactory = typeof(Expression)
.GetMethods()
// Filter overloads
.Single(x => x.ToString() == "System.Linq.Expressions.Expression`1[TDelegate] Lambda[TDelegate](System.Linq.Expressions.Expression, System.Linq.Expressions.ParameterExpression[])")
.MakeGenericMethod(myTypeArgument);
var lambda = (LambdaExpression) lambdaFactory.Invoke(
null,
new object[] {
...
// ,null
}
);
,我得到了TargetParameterCountException: Parameter count mismatch.。但是如果null作为另一个参数添加,它就可以完美地工作。
这对我来说有点奇怪。为什么 MS Docs 使用?(可选标记)?该params参数是否真的是可选的,类似于常规选项参数,例如string Foo(int a = 1); var result = Foo();?或者它只是一个语法糖?所以这就是为什么我可以直接Expression.Lambda<T>(...)在编辑器中调用,但编译的代码可以不同(这也与反射系统兼容)。如果是这样,这是否意味着该方法总是接收该null值,即使我没有指定值?但是,如果一个方法使用params参数,并且没有传递任何内容,则方法体中的参数是一个有效的数组,带有.Count == 0,而不是null。使用反射传递是否安全null,或者我应该创建一个空对象数组?