Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I programmatically do method overload resolution in C#?

Tags:

When the C# compiler interprets a method invocation it must use (static) argument types to determine which overload is actually being invoked. I want to be able to do this programmatically.

If I have the name of a method (a string), the type that declares it (an instance of System.Type), and a list of argument types I want to be able to call a standard library function and get back a MethodInfo object representing the method the C# compiler would choose to invoke.

For instance if I have

class MyClass {
  public void myFunc(BaseClass bc) {};
  public void myFunc(DerivedClass dc) {};
}

Then I want something like this fictional function GetOverloadedMethod on System.Type

MethodInfo methodToInvoke
  = typeof(MyClass).GetOverloadedMethod("myFunc", new System.Type[] {typeof(BaseClass)});

In this case methodToInvoke should be public void myFunc(BaseClass bc).

NOTE: Neither of the methods GetMethod and GetMethods will serve my purpose. Neither of them do any overload resolution. In the case of GetMethod it only returns exact matches. If you give it more derived arguments it will simply return nothing. Or you might be lucky enough to get an ambiguity exception which provides no useful information.

like image 240
Fizzy Avatar asked Apr 15 '15 23:04

Fizzy


1 Answers

Answer

Use Type.GetMethod(String name, Type[] types) to do programmatic overload resolution. Here is an example:

MethodInfo methodToInvoke = typeof(MyClass)
    .GetMethod("myFunc", new System.Type[] { typeof(BaseClass) });

Explanation

In the example, methodToInvoke will be myFunc(BaseClass bc) not myFunc(DerivedClass dc), because the types array specifies the parameter list of the method to get.

From the MSDN documentation, Type.GetMethod(String name, Type[] types) has two parameters:

  • name is the name of the method to get, and
  • types provides the order, number, and types of the method's parameters.

Running Code

Here is a running fiddle that demonstrates programmatic overload resolution.

using System;
using System.Reflection;

public static class Program
{
    public static void Main()
    {
        MethodInfo methodToInvoke = typeof(MyClass)
            .GetMethod("myFunc", new System.Type[] { typeof(BaseClass) });

        var result = methodToInvoke
            .Invoke(new MyClass(), new object[] { new BaseClass() });

        Console.WriteLine(result);      
    }

    public class MyClass
    {
        public static string myFunc(BaseClass bc) {
            return "BaseClass";
        }

        public static string myFunc(DerivedClass dc) {
            return "DerivedClass";
        }
    }

    public class BaseClass { }
    public class DerivedClass : BaseClass { }
}

The output is BaseClass.

Edit: This is robust.

GetMethod resolved methods that take params, more derived classes, delegates, and interface implementations. This Fiddle demonstrates all of those cases. Here are the calls and what they retrieve.

Works with params

MethodInfo methodToInvoke2 = typeof(MyClass).GetMethod(
        "myFunc",
        new System.Type[] { typeof(Int32[]) });

will resolve this method

public static string myFunc(params int[] i)
{
    return "params";
}

Works with more derived classes

MethodInfo methodToInvoke3 = typeof(MyClass).GetMethod(
    "myFunc", 
    new System.Type[] { typeof(MoreDerivedClass) });

resolves a method that takes the MoreDerivedClass

public class BaseClass { }
public class DerivedClass : BaseClass { }
public class MoreDerivedClass : DerivedClass {}

Works with delegates

MethodInfo methodToInvoke4 = typeof(MyClass).GetMethod(
    "myFunc", 
    new System.Type[] { typeof(MyDelegate) });

... will retrieve a method that takes this delegate:

public delegate void MyDelegate(string x);

Works with interface implementations

MethodInfo methodToInvoke5 = typeof(MyClass).GetMethod(
   "myFunc", 
   new System.Type[] { typeof(MyImplementation) });

... successfully retrieves a method that takes MyImplementation

public interface IMyInterface {}
public class MyImplementation : IMyInterface {}

So, it is robust, and we can use GetMethod to do overload resolution in cases that we might not expect to work.

like image 79
Shaun Luttin Avatar answered Oct 13 '22 02:10

Shaun Luttin