简体   繁体   中英

What is the signature of a method with params?

I was about to bind Expression.Lambda programmatically (because of unknown/variable type parameters), and found out that if the target method uses params , the reflected calling is a bit different than calling directly.

First, in the official documentation , the "signature" (although this is more like a XML-doc):

public static
System.Linq.Expressions.Expression<TDelegate>
    Lambda<TDelegate>(
        System.Linq.Expressions.Expression body,
        params System.Linq.Expressions.ParameterExpression[]? parameters
    );

Notice that it the 2nd param is marked as optional, and we can write Expression.Lambda<T>(...) . If in Visual Studio, you go to the disassembled declaration list, you can see this:

public static
Expression<TDelegate>
    Lambda<TDelegate>(
        Expression body,
        params ParameterExpression[] parameters
    );

2nd parameter is no longer marked as option. Now when I tried to invoke this method using reflection as:

    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
            }
        );

, I got TargetParameterCountException: Parameter count mismatch. . But if null is added as another parameter, it works perfectly.

This is a bit strange for me. Why does the MS Docs use ? (optional marker)? Is the params argument really optional similarly to regualr option arguments, like string Foo(int a = 1); var result = Foo(); string Foo(int a = 1); var result = Foo(); ? Or it is just a syntactic sugar? So that's why I may call directly Expression.Lambda<T>(...) in the editor, but the compiled code can be different (which is compatible with the reflection system too). If so, does that mean the method always receives the null value, even if I don't specify values? But if a method uses params argument, and nothing is passed, the argument from the method body is a valid array with .Count == 0 , not null . Is it safe to pass null using reflection, or I should create an empty object array?

The ? in the docs denote a nullable reference type , not an optional parameter. 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.

This explains why the ? disappears when you look at the "disassembled declaration list".

All ? tells you is that you can pass null to this parameter and the method will still work.

In this case, an alternative to passing null is to pass an empty array of ParameterExpression s:

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

This would reflect how you call Lambda non-reflectively:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM