19

I wrote the extension method GenericExtension. Now I want to call the extension method Extension. But the value of methodInfo is always null.

public static class MyClass
{
    public static void GenericExtension<T>(this Form a, string b) where T : Form
    {
        // code...
    }

    public static void Extension(this Form a, string b, Type c)
    {
        MethodInfo methodInfo = typeof(Form).GetMethod("GenericExtension", new[] { typeof(string) });
        MethodInfo methodInfoGeneric = methodInfo.MakeGenericMethod(new[] { c });
        methodInfoGeneric.Invoke(a, new object[] { a, b });
    }

    private static void Main(string[] args)
    {
        new Form().Extension("", typeof (int));
    }
}

Whats wrong?

David
  • 4,027
  • 10
  • 50
  • 102
  • See http://stackoverflow.com/questions/5959219/how-to-use-reflection-to-get-extension-method-on-generic-type?rq=1 for more info on that. – skarmats Apr 10 '13 at 13:23

3 Answers3

23

The extension method isn't attached to the type Form, it's attached to the type MyClass, so grab it off that type:

MethodInfo methodInfo = typeof(MyClass).GetMethod("GenericExtension",
    new[] { typeof(Form), typeof(string) });
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • 1
    Now I'm depressed... The solution is so simple and obvious Thank you – David Apr 10 '13 at 13:37
  • 1
    @David, no worries, you just got confused because it **feels like** the extension method is attached to the type `Form`. You just needed a second set of eyes. – Mike Perrenoud Apr 10 '13 at 13:38
  • How this will work? Extension methods can't be retrieved via GetMethod method... – Akmal Salikhov Dec 16 '20 at 11:57
  • Not work. `typeof(Enumerable).GetMethod(nameof(Enumerable.Contains), new[] { typeof(IEnumerable), typeof(int) })` return `null`. – huang Nov 23 '22 at 21:44
2

In case you have an extension method like

public static class StringExtensions
{
    public static bool IsValidType<T>(this string value);
}

you can invoke it (e. g. in tests) like so:

public class StringExtensionTests
{
    [Theory]
    [InlineData("Text", typeof(string), true)]
    [InlineData("", typeof(string), true)]
    [InlineData("Text", typeof(int), false)]
    [InlineData("128", typeof(int), true)]
    [InlineData("0", typeof(int), true)]
    public void ShouldCheckIsValidType(string value, Type type, bool expectedResult)
    {
        var methodInfo = 
            typeof(StringExtensions).GetMethod(nameof(StringExtensions.IsValidType),
            new[] { typeof(string) });
        var genericMethod = methodInfo.MakeGenericMethod(type);
        var result = genericMethod.Invoke(null, new[] { value });
        result.Should().Be(expectedResult);
    }
}
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
IngoB
  • 2,552
  • 1
  • 20
  • 35
0

Building off of @Mike Perrenoud's answer, the generic method I needed to invoke was not constrained to the same type as the class of the extension method (i.e. T is not of type Form).

Given the extension method:

public static class SqlExpressionExtensions
{
    public static string Table<T>(this IOrmLiteDialectProvider dialect)
}

I used the following code to execute the method:

private IEnumerable<string> GetTrackedTableNames(IOrmLiteDialectProvider dialectProvider)
{
    var method = typeof(SqlExpressionExtensions).GetMethod(nameof(SqlExpressionExtensions.Table), new[] { typeof(IOrmLiteDialectProvider) });

    if (method == null)
    {
        throw new MissingMethodException(nameof(SqlExpressionExtensions), nameof(SqlExpressionExtensions.Table));
    }

    foreach (var table in _trackChangesOnTables)
    {
        if (method.MakeGenericMethod(table).Invoke(null, new object[] { dialectProvider }) is string tableName)
        {
            yield return tableName;
        }
    }
}

where the types defined in _trackChangesOnTables are only known at runtime. By using the nameof operator, this protects against exceptions at runtime if the method or class is ever removed during refactoring.

Connor
  • 807
  • 1
  • 10
  • 20