5

We're currently using .NET 3.5 and part of our application uses dynamic invocation (using MethodBase.Invoke)

I am wondering if it is possible to mix in Named Parameters (in .NET 4) with dynamic invocation, to perform something similar to:

// Dictionary that holds parameter name --> object mapping
var parameters = new Dictionary<string, object>();

// Add parameters ....

// Invoke where each parameter will match the one from the method signature.
methodInfo.Invoke(obj, parameters);

Is there any API that allows this option out of the box? If not, is it possible to develop some solution to perform this?

EDIT:

Rethinking of this problem, it sounds similar to how the compiler may actually need to match method calls based on argument lists. Perhaps there's some Compiler API (or the new Roslyn project) that allows doing just this easily? (without coding it myself which may be prone to errors).

svick
  • 236,525
  • 50
  • 385
  • 514
lysergic-acid
  • 19,570
  • 21
  • 109
  • 218

3 Answers3

21

You can use code like this:

public static class ReflectionExtensions {

    public static object InvokeWithNamedParameters(this MethodBase self, object obj, IDictionary<string, object> namedParameters) { 
        return self.Invoke(obj, MapParameters(self, namedParameters));
    }

    public static object[] MapParameters(MethodBase method, IDictionary<string, object> namedParameters)
    {
        string[] paramNames = method.GetParameters().Select(p => p.Name).ToArray();
        object[] parameters = new object[paramNames.Length];
        for (int i = 0; i < parameters.Length; ++i) 
        {
            parameters[i] = Type.Missing;
        }
        foreach (var item in namedParameters)
        {
            var paramName = item.Key;
            var paramIndex = Array.IndexOf(paramNames, paramName);
            if (paramIndex >= 0)
            {
                parameters[paramIndex] = item.Value;
            }
        }
        return parameters;
    }
}

And then call it like this:

var parameters = new Dictionary<string, object>();
// Add parameters ...
methodInfo.InvokeWithNamedParameters(obj, parameters);
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • What would happen if the method uses default parameter values (.NET 4 feature)? does this solution work in that case? (can it differentiate between a null passed parameter, to a parameter that should not be passed (and thus take the default value)? I am not sure, but i will take the code and test that! – lysergic-acid Oct 25 '12 at 16:41
  • @lysergic-acid: look [here](http://stackoverflow.com/questions/2421994/invoking-methods-with-optional-parameters-through-reflection/2422015#2422015) for some ideas. – Jordão Oct 25 '12 at 16:44
  • awesome so basically i can amend your example to reflect for these attributes and get the default value into the array in any case. Thanks! – lysergic-acid Oct 25 '12 at 16:47
  • I've changed the code to initialize the parameters with `Type.Missing` to account for optional parameters. But I haven't tested it, please check that it works. – Jordão Oct 25 '12 at 16:49
  • 1
    You might want to check if `paramIndex != -1` before you set the value to prevent `IndexOutOfRangeException`. – Fred Apr 16 '16 at 23:25
  • @Fred: You're absolutely right, a more robust implementation would need to not only do that but also check if `namedParameters` is null and many other boundary conditions. – Jordão Apr 16 '16 at 23:51
  • What other boundary conditions? Given inputs of a MethodBase (literally any instance) and a dictionary populated with virtually any parameter names and objects, the ONLY thing you'd really need to check here for this to not blow up is that `paramIndex > -1`. If you simply added that one thing that the last comment asked for, this would simply work. It would ignore parameters in the dictionary that don't match any in the method, and would just work as expected. Valid arguments would always make it to the correct place, and beyond that, it's outside the responsibility of this method. – Triynko Oct 17 '19 at 02:45
  • Hey @Triynko, makes sense! Edited the answer. – Jordão Oct 17 '19 at 11:08
1

you can get your paramter names with the help of this article How can you get the names of method parameters? and then you can reorder them to invoke them as described here Reflection: How to Invoke Method with parameters

Community
  • 1
  • 1
TGlatzer
  • 5,815
  • 2
  • 25
  • 46
1

With .net4, I have an opensource framework ImpromptuInterface (found in nuget) that makes it easy to use the DLR apis for late invocation including named/optional parameters.

var result = Impromptu.InvokeMember(target, "MyMethod", parameters.Select(pair=>  InvokeArg.Create(pair.Key, pair.Value)).Cast<object>().ToArray());
jbtule
  • 31,383
  • 12
  • 95
  • 128