Получить только прямой интерфейс вместо всех? - PullRequest
19 голосов
/ 16 марта 2011

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

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

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

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

Ответы [ 5 ]

28 голосов
/ 16 марта 2011

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

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

class ABC : DEF, GHI {...}

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

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

Type type = ...

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

( РЕДАКТИРОВАТЬ - Вот лучший способ сделать выше:

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

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

Например, скажем, у нас есть:

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

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

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

3 голосов
/ 16 марта 2011

Это хорошая часть из дублирующего вопроса :

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);
}
0 голосов
/ 06 сентября 2016

Этот вопрос дублируется и здесь и здесь . В любом случае, вот мой краткий код, который учитывает моменты, поднятые в этой теме @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;
0 голосов
/ 31 мая 2013

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

    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; }
    }
0 голосов
/ 16 марта 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...