jeudi 24 décembre 2020

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();? 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?





Aucun commentaire:

Enregistrer un commentaire