假设我有一个类似的课程:
public class MyClass<T>
{
public void Foo(T t)
{
}
}
现在,假设我有一个MyClass<int>
的实例和MethodInfo
方法的Foo
。
调用methodInfo.GetParameters()
将返回带有一个条目的ParameterInfo
数组,引用类型int
。我的问题是,如果该参数在类中声明为int
或T
,我似乎无法找到。
我想要实现的目标是什么?
在运行时,我想从Visual Studio生成的XML Doc文件中读取MethodInfo
指定的方法的文档。
对于上面定义的方法,键如下所示:
<namespace>.MyClass`1.Foo(`0)
`0
是指声明类的第一个泛型类型参数。为了能够构造这个字符串,我需要以某种方式获取这些信息
但是如何? MethodInfo
似乎不包含该信息...
答案 0 :(得分:3)
参数类型上的键似乎是Type.ContainsGenericParameters
:
鉴于
public class MyClass<T>
{
public void Foo(T t)
{
}
public void Bar(int i)
{
}
}
然后
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();
}
}
输出
True
False
这显然需要更多的工作来处理重载等问题。
答案 1 :(得分:1)
您是否可以通过Type.GetGenericTypeDefinition Method获取泛型类的定义,并找到相同方法的定义,例如,按名称(和签名),然后比较Foo(T t)
和{{1 }}:
Foo(int t)
答案 2 :(得分:1)
我不知道你是否考虑过使用Mono.Cecil而不是.Net的反思。
// 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");
然后myMethodDef.FullName
返回
"System.Void MyNamespace.MyClass`1::Foo(System.Int32,T,System.String)"
和classDef.GenericParameters[0].FullName
返回
"T"
请注意,Mono.Cecil使用不同的方式编写泛型,嵌套类和数组:
List[T] => List<T>
MyClass+MyNestedClass => MyClass/MyNestedClass
int[,] => int[0...,0...]
答案 3 :(得分:0)
这是一个棘手的问题。如果您有( non- 通用)方法的MethodInfo
实例,该实例是通过 open通用获取的> Type
,您实际上可以 使用它来重复关闭该方法(即,对于 enclosing 类型使用不同的通用参数)。>
关键是使用模糊的静态函数MethodInfo.GetMethodFromHandle(...)
:
完整的工作示例:
static class SomeType<T>
{
public static int NonGenericMethod() => typeof(T).MetadataToken;
};
使用方法:
static void demo()
{
var Topen = typeof(SomeType<>);
var mi_nope = Topen.GetMethod("NonGenericMethod"); // cannot 'Invoke' this.
/// ...later perhaps...
var Tclosed = Topen.MakeGenericType(typeof(ushort));
var mi_ok = MethodInfo.GetMethodFromHandle(mi_nope.MethodHandle, Tclosed.TypeHandle);
var ret = (int)mi_ok.Invoke(null, null); // --> 0x02000150
/// ...again with a different generic arg, reusing 'mi_wontInvoke' (and Topen)...
Tclosed = Topen.MakeGenericType(typeof(Guid));
mi_ok = MethodInfo.GetMethodFromHandle(mi_nope.MethodHandle, Tclosed.TypeHandle);
ret = (int)mi_ok.Invoke(null, null); // --> 0x020000eb
}
请注意,Tclosed
类型的句柄(作为第二个arg传入)不仅仅是您最终希望对其进行参数化的类型参数T
的句柄。相反,您必须先使用该T
来关闭原始的Topen
(打开)泛型类型,然后使用生成的(关闭)泛型类型的句柄。
换句话说,您必须先明确关闭其通用类型,才能关闭该通用方法。