К сожалению, System.Reflection не предоставляет хорошего способа соотнести метод для составного типа с соответствующим методом в определении универсального типа, из которого он был создан. Я знаю два решения, ни одно из которых не является идеальным:
Решение № 1: статический TypeBuilder.GetMethod. Существует статическая версия GetMethod для TypeBuilder , которая принимает универсальный составной тип и MethodInfo для метода в определении универсального типа, и возвращает
соответствующий метод для указанного универсального типа. В этом примере вызов TypeBuilder.GetMethod(Foo<int>, Foo<T>.Bar(T))
даст вам Foo<int>.Bar(T-as-int)
, который вы затем сможете использовать для устранения неоднозначности между ним и Foo<int>.Bar(int)
.
(Приведенный выше пример, естественно, не будет компилироваться; я использовал Foo<int>
и Foo<T>.Bar(T)
для обозначения соответствующих объектов Type и MethodInfo, которые легко доступны, но могут сделать пример слишком сложным).
Плохая новость заключается в том, что это работает только тогда, когда определение универсального типа представляет собой TypeBuilder, то есть когда вы генерируете универсальный тип.
Решение # 2: MetadataToken. Это малоизвестный факт, что члены типа сохраняют свой MetadataToken при переходе от определений универсальных типов к обобщенным составным типам. Таким образом, в вашем примере Foo<T>.Bar(T)
и Foo<int>.Bar(T-as-int)
должны использовать один и тот же MetadataToken. Это позволит вам сделать это:
var barWithGenericParameterInfo = typeof(Foo<>).GetMethods()
.Where(mi => mi.Name == "Bar" &&
mi.GetParameters()[0].ParameterType.IsGenericParameter);
var mappedBarInfo = foo.GetType().GetMethods()
.Where(mi => mi.MetadataToken == genericBarInfo.MetadataToken);
(Это тоже не скомпилируется, если только мне не повезет и мне не удалось сделать все правильно с первого раза :))
Проблема с этим решением заключается в том, что MetadataToken не был предназначен для этого (вероятно, документация немного скудна), и это похоже на грязный хак. Тем не менее, это работает.