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?

1

3 Answers 3

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) });
Sign up to request clarification or add additional context in comments.

4 Comments

Now I'm depressed... The solution is so simple and obvious Thank you
@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.
How this will work? Extension methods can't be retrieved via GetMethod method...
Not work. typeof(Enumerable).GetMethod(nameof(Enumerable.Contains), new[] { typeof(IEnumerable<int>), typeof(int) }) return null.
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);
    }
}

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.