I have a class with few generic overloaded methods. I am trying to get a specific one by types of its parameters. It's relatively easy to do, when I stick to the first two (with arguments of type int and string). But no matter what I do I cannot get my program to notice the third one, intended for generic list. Do I use a wrong Type argument? If so what is a correct way?
/* 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)
{
}
}
Short version: typeof(IEnumerable<>)
is not the same as typeof(IEnumerable<T>)
(for some T
).
Longer version: there is no method void c.m(IEnumerable<> Ls)
, only overloads where the generic parameter will be some specific – existing at run time – type where the jitter has needed to create the method due to some code referencing that instantiation of the generic method.
Add a call, in your test code, to some instance of the generic method and then do a GetMethod
for that instance.
Consider the following:
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}");
}
}
}
}
which produces the output:
M Int32 M IEnumerable`1
Note there is only one result from the generic overload. If a call to M<char>(…)
is added to Main
then the output is the same.
For reflection there is just one method, are its argument reflects its "open generic" nature, but that isn't quite the same as being callable with an open generic type (eg. IEnumerable<>
) as open types are not instantiatable.
(I've fudged much of the technical details here. It is instruictive to look at the difference in a debugger between typeof(IEnumerable<>)
and typeof(IEnumerable<int>)
.)