带参数的方法的签名是什么?

What is the signature of a method with params?

我正要以编程方式绑定Expression.Lambda(因为unknown/variable类型参数),发现如果目标方法使用params,反射调用有点不同而不是直接调用。

首先,在 official documentation 中,“签名”(尽管这更像是 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 是否安全,或者我应该创建一个空对象数组?

文档中的 ? 表示 可为 null 的引用类型 ,而不是可选参数。 Nullable reference types are purely a "compile-time check" thing, and at runtime, they are no different from regular old reference types.:

Nullable reference types aren't new class types, but rather annotations on existing reference types. The compiler uses those annotations to help you find potential null reference errors in your code. There's no runtime difference between a non-nullable reference type and a nullable reference type. The compiler doesn't add any runtime checking for non-nullable reference types. The benefits are in the compile-time analysis. The compiler generates warnings that help you find and fix potential null errors in your code. You declare your intent, and the compiler warns you when your code violates that intent.

这就解释了为什么在查看“反汇编声明列表”时 ? 消失了。

所有 ? 告诉您的是,您可以将 null 传递给此参数,该方法仍然有效。

在这种情况下,传递 null 的替代方法是传递 ParameterExpressions:

的空数组
var lambda = (LambdaExpression) lambdaFactory.Invoke(
        null,
        new object[] {
            someBodyExpression,
            new ParameterExpression[] { }
        }
    );

这将反映您如何非反射地调用 Lambda

// I'm passing no extra arguments, so an empty array is passed to the "params" parameter
Lambda<T>(someBodyExpression)