Как определить, на какой интерфейс ссылается явно реализованный объект MethodInfo? - PullRequest
1 голос
/ 26 декабря 2009

У меня есть MethodInfo объект, который представляет явно реализованный метод интерфейса, следующим образом.

MethodInfo GetMethod()
{
    return typeof(List<>).GetMethod(
        "System.Collections.IEnumerable.GetEnumerator",
        BindingFlags.Instance | BindingFlags.NonPublic);
}

Как мне запросить этот MethodInfo объект, чтобы получить тип интерфейса, который он реализует, Type объект, представляющий System.Collections.IEnumerable? Структура InterfaceMapping обеспечивает обратную операцию, получая объект MethodInfo типа, который реализует данный интерфейс, поэтому он не будет работать.

Обратите внимание, что это надуманный пример, так как я могу четко разобрать имя метода для этой информации. Я хотел бы избежать этого, если это возможно.

Ответы [ 3 ]

4 голосов
/ 26 декабря 2009

Я не знаю прямого способа сделать это, но вы, очевидно, можете использовать InterfaceMapping в обратном порядке: переберите все интерфейсы, реализованные объявленным типом метода, проверяя, находится ли метод в карте интерфейса для этого интерфейса:

foreach (Type itf in method.DeclaringType.GetInterfaces())
{
  if (method.DeclaringType.GetInterfaceMap(itf).TargetMethods.Any(m => m == method))
  {
    Console.WriteLine("match: " + itf.Name);
  }
}

Хотя это может показаться немного неэффективным, большинство типов реализуют достаточно мало интерфейсов, поэтому это не должно иметь большого значения. Цени это не очень элегантно, хотя!

1 голос
/ 26 декабря 2009

Извините за мой первый ответ, сначала я попытался добраться до метода через структуру InterfaceMap, а методы в , которые структура на самом деле делают , сообщают интерфейс как DeclaringType. Тогда я возился с этим и не понял, что он был слегка сломан, используя метод, который вы опубликовали, чтобы получить MethodInfo.

Однако положительным моментом является то, что это тонкое различие привело к осознанию того, что MethodInfo для метода интерфейса и MethodInfo для метода реализации на самом деле не являются одним и тем же методом. И если подумать, я на самом деле почти уверен, что то, что вы хотите сделать, невозможно сделать надежно.

Явные реализации интерфейса в C # представляют собой немного синтаксического сахара по сравнению с тем, как он действительно работает в CLR. В других языках один конкретный метод может реализовывать несколько методов интерфейса так же, как конкретный класс может реализовывать несколько типов интерфейса. Например, в VB.NET это совершенно законно:

Public Overrides Function Baz() As String Implements IFoo.Foo, IBar.Bar

Здесь у вас есть один метод, который явно реализует два метода интерфейса. Если бы можно было получить оригинальный интерфейсный класс - или даже оригинальный интерфейсный метод - какой бы вы получили? Как вы решаете двусмысленность?

Я не эксперт по внутренним компонентам CLR, но я считаю, что карты интерфейсов односторонние. Когда вы реализуете интерфейс или метод, неявно или явно, компилятор создает карту от интерфейса до реализации, и это все, что ему когда-либо нужно для обработки вызовов методов для интерфейса.

Представьте, что сгенерированные в C # имена методов являются почти случайными. Хотя имя метода System.Collections.IEnumerable.GetEnumerator, на самом деле это просто имя, и на самом деле никакой информации о System.Collections.IEnumerable, закодированной в самом методе, нет.

0 голосов
/ 26 декабря 2009

Попробуйте MethodInfo.DeclaringType.

...