Подтвердить что ты не робот

Получить только прямой интерфейс вместо всех?

У меня есть класс, как показано ниже. GetInterfaces() говорит

Если текущий тип представляет тип параметра в определении a общий тип или общий метод, это метод ищет интерфейс ограничения и любые интерфейсы унаследованный от класса или интерфейса ограничения.

Возможно ли, чтобы я не получил никакого унаследованного интерфейса? Когда я использую GetInterfaces на ABC, я хочу видеть только DEF, а не DEF и GHI.

interface DEF : GHI {...}
class ABC : DEF {...}
4b9b3361

Ответ 1

Во-первых, фрагмент MSDN, который вы опубликовали, не имеет никакого отношения к вашему фактическому вопросу. Он имеет дело с тем, что у вас есть, например, общий тип, например class Foo<T> where T : IEnumerable, и вы пытаетесь вызвать GetInterfaces для параметра типа T, например, через typeof(Foo<>).GetGenericArguments().Single().GetInterfaces().

Во-вторых, проблема слегка не указана. Обратите внимание: когда класс реализует интерфейс, он должен реализовать все наследуемые интерфейсы этого интерфейса. Это просто удобная функция С#, которая позволяет опускать наследуемые интерфейсы в декларации класса. В вашем примере он совершенно легален (и не отличается), чтобы явно включать интерфейс "унаследованный" GHI:

class ABC : DEF, GHI {...}

Я предположил, что вы действительно хотите найти "минимальный набор" интерфейсов, который "покрывает" все интерфейсы, реализованные на типе. Это приводит к слегка упрощенной версии Задайте проблему обложки.

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

Type type = ...

var allInterfaces = type.GetInterfaces();    
var minimalInterfaces = from iType in allInterfaces 
                        where !allInterfaces.Any(t => t.GetInterfaces()
                                                       .Contains(iType))
                        select iType;

( EDIT. Здесь лучший способ сделать это:

var minimalInterfaces = allInterfaces.Except
                        (allInterfaces.SelectMany(t => t.GetInterfaces()));

)

Например, для List<int>:

allInterfaces: 

System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
System.Collections.IEnumerable
System.Collections.IList
System.Collections.ICollection

minimalInterfaces:

System.Collections.Generic.IList`1[System.Int32]
System.Collections.IList

Обратите внимание, что это решение охватывает только иерархии интерфейсов (что вам кажется нужным), а не то, как они относятся к иерархии классов классов. В частности, он не обращает внимания на то, где в иерархии классов сначала был реализован интерфейс.

Например, допустим, что мы имеем:

interface IFoo { }
interface IBar : IFoo { }
interface IBaz { } 

class Base : IBar {  }
class Derived : Base, IBaz {  }

Теперь, если вы попытаетесь использовать решение, которое я описал, чтобы получить минимальный набор интерфейсов для Derived, вы получите IBaz, а также IBar. Если вы не хотите IBar, вам нужно будет приложить больше усилий: устранить интерфейсы, реализуемые базовыми классами. Самый простой способ сделать это - удалить из минимального интерфейса - установить те интерфейсы, которые реализуются классом немедленного базового класса, как указано в ответе @MikeEast.

Ответ 2

Это хороший фрагмент из повторяющегося вопроса:

public static class TypeExtensions {
   public static IEnumerable<Type> GetInterfaces(this Type type, bool includeInherited)
   {
      if (includeInherited || type.BaseType == null)
         return type.GetInterfaces();
      else
         return type.GetInterfaces().Except(type.BaseType.GetInterfaces());
   }
}

И использование:

foreach(Type ifc in typeof(Some).GetInterfaces(false)) {
   Console.WriteLine(ifc);
}

Ответ 3

На той же странице MSDN

Метод GetInterfaces не обратные интерфейсы в определенном порядок, например, алфавитный или порядок объявления. Ваш код не должен зависят от порядка, в котором интерфейсы возвращаются, поскольку порядок меняется.

Нет, вы не можете пропускать интерфейсы.

Ответ 4

Как насчет этого для интерфейса наследования heirachy?

    public static Map GetTypeInheritance(Type type)
    {
        //get all the interfaces for this type
        var interfaces = type.GetInterfaces();

        //get all the interfaces for the ancestor interfaces
        var baseInterfaces = interfaces.SelectMany(i => i.GetInterfaces());

        //filter based on only the direct interfaces
        var directInterfaces = interfaces.Where(i => baseInterfaces.All(b => b != i));

        Map map = new Map
            {
                Node = type,
                Ancestors = directInterfaces.Select(GetTypeInheritance).ToList()
            };

        return map;
    }

    public class Map
    {
       public Type Node { get; set; }
       public List<Map> Ancestors { get; set; }
    }

Ответ 5

Этот вопрос дублируется как здесь и здесь. В любом случае, здесь мой сжатый код, который рассматривает точки, поднятые в этом потоке by @Ani и @Mikael:

var actualInterfaces = type.GetInterfaces();
foreach ( var result in actualInterfaces
    .Except( type.BaseType?.GetInterfaces() ?? Enumerable.Empty<Type>() ) //See https://stackoverflow.com/a/1613936
    .Except( actualInterfaces.SelectMany( i => i.GetInterfaces() ) ) //See https://stackoverflow.com/a/5318781
) yield return result;