C#:GetMethod按类型(通用列表)

时间:2016-09-22 08:27:28

标签: c# system.reflection

我有一个几乎没有通用重载方法的类。我试图通过其参数类型获得特定的一个。当我坚持前两个(带有int和string类型的参数)时,它相对容易做到。但无论我做什么,我都无法让我的程序注意到第三个,用于通用列表。我使用了错误的Type参数吗?如果是这样,什么是正确的方法?

/* rest of code */
    static void Main(string[] args) {
        MethodInfo method =
            typeof(c).GetMethod("m", new Type[] { typeof(int) });

        Console.WriteLine(method);

        method =
            typeof(c).GetMethod("m", new Type[] { typeof(String) });

        Console.WriteLine(method);

        method =
            typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) });

        Console.WriteLine(method);

        Console.ReadKey();
    }
}

static class c
{
    public static void m<T>(int i)
    {
    }

    public static void m<T>(String s)
    {
    }

    public static void m<T>(IEnumerable<T> Ls)
    {
    }
}

3 个答案:

答案 0 :(得分:1)

简短版本:typeof(IEnumerable<>)typeof(IEnumerable<T>)不同(对于某些T)。

更长的版本:没有方法void c.m(IEnumerable<> Ls),只有通用参数特定的重载 - 在运行时存在 - 由于某些代码引用实例化而导致创建方法所需的抖动类型通用方法。

在测试代码中添加一个调用泛型方法的某个实例,然后为该实例执行GetMethod

请考虑以下事项:

using System.Collections.Generic;
using System.Linq;
using static System.Console;

class Methods {
    public static void M(int x)     {
        // no-op
    }

    public static void M<T>(IEnumerable<T> x)     {
        // no-op
    }
}

class Program {
    static void Main(string[] args)  {
        Methods.M(0);
        Methods.M(new[] { "a", "b" });

        ShowAllM();
    }

    public static void ShowAllM() {
        var tm = typeof(Methods);
        foreach (var mi in tm.GetMethods().Where(m => m.Name == "M"))
        {
            WriteLine(mi.Name);
            foreach (var p in mi.GetParameters())
            {
                WriteLine($"\t{p.ParameterType.Name}");
            }
        }
    }
}

产生输出:

M
    Int32
M
    IEnumerable`1

请注意,泛型重载只有一个结果。如果M<char>(…)的{​​{1}}被添加到Main,则输出相同

对于反射,只有一种方法,它的参数反映了它的“开放通用”性质,但这与使用开放泛型类型(例如。IEnumerable<>)可调用的开放类型不完全相同不可实例化。

(我在这里捏造了大部分技术细节。在typeof(IEnumerable<>)typeof(IEnumerable<int>)之间查看调试器的区别是有用的。)

答案 1 :(得分:1)

第三种方法的签名为m<T>(IEnumerable<T>),但您的示例显示了尝试查找带有签名m(IEnumerable<>)的方法。

typeof(IEnumerable<T>)typeof(IEnumerable<>)之间的区别是前者是泛型类型,第二种是泛型类型定义,这些不是同一个东西。泛型类型由泛型类型定义和泛型类型参数确定。

考虑到这一点,你会想要使用:

method =
        typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) });

并替换您将传递给方法的枚举类型。

另一方面,如果你不知道前面可枚举的类型,你可以得到泛型方法定义,并在需要时制作可用的泛型方法:

methodDef =
        typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition();
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) });

答案 2 :(得分:0)

如果从int和string方法中删除通用defenitions:

    return RxTextView.textChanges(editText).switchMap(charSequence -> 
          realm.where(Dog.class)
                    .contains(DogFields.NAME, charSequence.toString())
                    .findAllAsync()
                    .asObservable()
    ).filter(RealmResults::isLoaded) 
     .subscribe(dogs -> {
          adapter.updateData(dogs);
     });

并使用以下行来获得所需的通用方法:

    public static void m(int i)
    {
    }

    public static void m(String s)
    {
    }

    public static void m<T>(IEnumerable<T> Ls)
    {
    }

这样就可以了解