Как сформировать дерево, представляющее дерево наследования интерфейса? - PullRequest
2 голосов
/ 05 ноября 2010

Я знаю, как получить все интерфейсы T, используя typeof(T).GetInterfaces(), но мне нужно точное дерево наследования.
Возможно ли это как-то решить из существующего API отражения?

EDIT: Позвольте мне уточнить:

interface Base1 {}
interface Base2 {}
interface Foo : Base1
interface Final : Foo, Base2

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

1 Ответ

1 голос
/ 05 ноября 2010

Посмотрим.Насколько я знаю, нет никакого способа BCL только получить интерфейсы, которые фактически реализованы для определенного типа, но исключают любые интерфейсы, которые наследуются этим типом.Таким образом, нам придется бросить наше собственное:

public static Dictionary<Type, IEnumerable<Type>> GetInterfaceHierarchyMap(this Type type)
{
    List<Type> typeAncestry = new List<Type>();
    Type ancestor = type;
    while(ancestor != null)
    {
        typeAncestry.Add(ancestor);
        ancestor = ancestor.BaseType;
    }
    Dictionary<Type, IEnumerable<Type>> interfaceMaps = new Dictionary<Type, IEnumerable<Type>>();
    foreach(Type childType in typeAncestry.Reverse<Type>())
    {
        var mappedInterfaces = interfaceMaps.SelectMany(kvp => kvp.Value);
        var allInterfacesToPoint = childType.GetInterfaces();
        interfaceMaps.Add(childType, allInterfacesToPoint.Except(mappedInterfaces));
    }
    return interfaceMaps;
}

Один шаг за раз:

  1. Мы начинаем с текущего типа и поднимаемся по BaseType пока мы не достигнем корневого типа.
  2. Мы переворачиваем список, поэтому, когда мы перебираем его, мы сначала начинаем с корневого типа.
  3. Для каждого типа вниз по цепочке мы получаем все интерфейсыприменяется к этому типу и наследуется от типов-предков, затем мы используем Кроме , чтобы исключить все те, которые мы уже нашли в предыдущих итерациях.

Это будет рассматривать дублированные требования интерфейса как излишние -т. е. если один из ваших типов-предков реализует IDisposable, а ваш тип - тоже, будет учитываться только самая ранняя реализация.

Гипотетическим результатом этого метода будет словарь, который выглядит примерно так:

[object] - []
[BaseBaseClass] - [ISomeInterface]
[BaseClass] - [IAnotherInterface, IOneMore]
[ConcreteClass] - [IYetAnother]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...