How to get MethodInfo for open generic type from MethodInfo of closed type
The key seems to be Type.ContainsGenericParameters
on the parameter type:
Given
public class MyClass<T>
{
public void Foo(T t)
{
}
public void Bar(int i)
{
}
}
Then
class Program
{
static void Main(string[] args)
{
var obj = new MyClass<int>();
// Closed type
var closedType = obj.GetType();
// Open generic (typeof(MyClass<>))
var openType = closedType.GetGenericTypeDefinition();
// Methods on open type
var fooT = openType.GetMethod("Foo");
var barint = openType.GetMethod("Bar");
// Parameter types
var tInFoo = fooT.GetParameters()[0].ParameterType;
var iInBar = barint.GetParameters()[0].ParameterType;
// Are they generic?
var tInFooIsGeneric = tInFoo.ContainsGenericParameters;
var iInBarIsGeneric = iInBar.ContainsGenericParameters;
Console.WriteLine(tInFooIsGeneric);
Console.WriteLine(iInBarIsGeneric);
Console.ReadKey();
}
}
outputs
True
False
This will obviously need more work for overloads and so on.
Could you get the definition of the generic class through Type.GetGenericTypeDefinition Method and find there the definition for the same method, say, by name (and the signature), and then compare Foo(T t)
and Foo(int t)
:
MyClass<int> c = new MyClass<int>();
Type concreteType = c.GetType();
Console.Write("Concrete type name:");
Console.WriteLine(concreteType.FullName);
Console.WriteLine();
MethodInfo concreteMethod = concreteType.GetMethod("Foo");
if (concreteMethod != null)
{
Console.WriteLine(concreteMethod.Name);
foreach (ParameterInfo pinfo in concreteMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
if (concreteType.IsGenericType)
{
Console.Write("Generic type name:");
Type genericType = concreteType.GetGenericTypeDefinition();
Console.WriteLine(genericType.FullName);
Console.WriteLine();
MethodInfo genericMethod = genericType.GetMethod("Foo");
if (genericMethod != null)
{
Console.WriteLine(genericMethod.Name);
foreach (ParameterInfo pinfo in genericMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
}
I don't know if you have considered using Mono.Cecil instead of .Net's reflection.
// Gets the AssemblyDefinition (similar to .Net's Assembly).
Type testType = typeof(MyClass<>);
AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(new Uri(testType.Assembly.CodeBase).LocalPath);
// Gets the TypeDefinition (similar to .Net's Type).
TypeDefinition classDef = assemblyDef.MainModule.Types.Single(typeDef => typeDef.Name == testType.Name);
// Gets the MethodDefinition (similar to .Net's MethodInfo).
MethodDefinition myMethodDef = classDef.Methods.Single(methDef => methDef.Name == "Foo");
then myMethodDef.FullName
returns
"System.Void MyNamespace.MyClass`1::Foo(System.Int32,T,System.String)"
and classDef.GenericParameters[0].FullName
returns
"T"
Note that Mono.Cecil uses a different way of writing generics, nested classes and arrays:
List[T] => List<T>
MyClass+MyNestedClass => MyClass/MyNestedClass
int[,] => int[0...,0...]