Как получить MethodInfo для открытого универсального типа из MethodInfo закрытого типа
Предположим у меня есть класс следующим образом:
public class MyClass<T>
{
public void Foo(T t)
{
}
}
теперь предположим, что у меня есть экземпляр MyClass<int>
и MethodInfo
его Foo
метод.
Зову methodInfo.GetParameters()
вернет ParameterInfo
массив с одной записью, относящейся к типу int
. Моя проблема в том, что я не могу узнать, был ли этот параметр объявлен как int
в классе или как T
.
чего я пытаюсь достичь?
Во время выполнения, я хочу прочитать документацию метод, указанный MethodInfo
из XML-файла Doc, созданного Visual Studio.
Для указанного выше метода ключ выглядит следующим образом:
<namespace>.MyClass`1.Foo(`0)
на `0
относится к первому параметру универсального типа объявляющего класса. Чтобы построить эту строку, мне нужно как-то получить эту информацию.
но как? MethodInfo
не содержит этой информации...
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
это, очевидно, потребуется больше работы для перегрузок и так далее.
не могли бы вы сделать определение универсального класса через тип.GetGenericTypeDefinition Метод и найти там определение для того же метода, скажем, по имени (и подписи), а затем сравнить Foo(T t)
и 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();
}
}
Я не знаю, рассматривали ли вы использование Mono.Сесил вместо отражения .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.Сесил использует другой способ написания дженериков, вложенных классов и массивов:
List[T] => List<T>
MyClass+MyNestedClass => MyClass/MyNestedClass
int[,] => int[0...,0...]