How to resolve generic method ambiguity in C# reflection

I have two generic method overloads, that differ by the number of generic type parameters and argument type

// Argument types
public class Bar<T> {}
public class Bar<T, U> {}

// Generic method overloads
private static void Foo<T> (Bar<T> b) {}
private static void Foo<T, U> (Bar<T, U> b) {}

I’m assuming that i can get the method info for either one by using the appropriate number of type parameters

BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Static;

// Should give Foo<int>
GetType ().GetMethod ("Foo", Flags).MakeGenericMethod (typeof(int));

// Should give Foo<int, int>
GetType ().GetMethod ("Foo", Flags | BindingFlags.Static).MakeGenericMethod (typeof(int), typeof(int));

However this fails with System.Reflection.AmbiguousMatchException.

I tried specifying things like new Type[] {typeof (Bar<,>)} as the types argument for some of the GetMethod overloads , but the result was always null. I know i can workaround the ambiguity simply by using different names for the functions, but i’m interested to know if there’s an actual solution to this.

I’m on .NET standard 2.0, .NET Core 2.0

Answer

If you don’t want to use Type.GetMethods and iterate over the results you can use this overload of GetMethod and Type.MakeGenericMethodParameter which is available from .NET Core 2.1:

class MyClass
{
    // Argument types
    public class Bar<T> { }
    public class Bar<T, U> { }

    // Generic method overrides
    private static void Foo<T>(Bar<T> b) { }
    private static void Foo<T, U>(Bar<T, U> b) { }
}

typeof(MyClass)
    .GetMethod(
    "Foo",
    1,
    BindingFlags.NonPublic | BindingFlags.Static,
    null,
    new[] { Type.MakeGenericSignatureType(typeof(MyClass.Bar<>), Type.MakeGenericMethodParameter(0)) },
    null
); // First Foo

typeof(MyClass)
    .GetMethod(
    "Foo",
    2,
    BindingFlags.NonPublic | BindingFlags.Static,
    null,
    new[] { Type.MakeGenericSignatureType(typeof(MyClass.Bar<,>), Type.MakeGenericMethodParameter(0),Type.MakeGenericMethodParameter(1)) },
    null
); // Second Foo

UPD

Since Type.MakeGenericMethodParameter is not available for you the only option I see (if every method is not a part of generic class with the same generic type arguments) is to use GetMethods and filter the results. Simplest filter in this case would be number of generic parameters;

var secondMethod = typeof(MyClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
    .Where(mi => mi.Name == "Foo" && mi.GetGenericArguments().Length == 2)
    .First();