如何使用反射调用通用扩展方法?

19

我编写了扩展方法GenericExtension。现在我想调用扩展方法Extension。但是methodInfo的值始终为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));
    }
}

有什么问题吗?


有关此问题的更多信息,请参见https://dev59.com/im025IYBdhLWcg3whGWx?rq=1。 - skarmats
3个回答

23

扩展方法未附加到类型Form,而是附加到类型MyClass,因此请从该类型中获取它:

MethodInfo methodInfo = typeof(MyClass).GetMethod("GenericExtension",
    new[] { typeof(Form), typeof(string) });

1
现在我感到沮丧...解决方案是如此简单和明显。谢谢。 - David
1
@David,别担心,你只是有点糊涂,因为它“感觉上”扩展方法附加到了类型“Form”。你只需要再看一眼就可以了。 - Mike Perrenoud
这会怎么工作?扩展方法无法通过GetMethod方法检索... - Akmal Salikhov
不起作用。typeof(Enumerable).GetMethod(nameof(Enumerable.Contains), new[] { typeof(IEnumerable<int>), typeof(int) }) 返回 null - huang

2

如果您有一个扩展方法,例如

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

您可以像这样调用它(例如在测试中):

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);
    }
}

0
继承@Mike Perrenoud的答案,我需要调用的通用方法不受限于扩展方法所在类的相同类型(即T不是Form类型)。
给定扩展方法:
public static class SqlExpressionExtensions
{
    public static string Table<T>(this IOrmLiteDialectProvider dialect)
}

我使用以下代码执行该方法:
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;
        }
    }
}

_trackChangesOnTables 中定义的类型仅在运行时才知道。使用 nameof 运算符可以防止在重构期间删除方法或类时出现运行时异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接