Get only direct interface instead of all?

前端 未结 6 2272
借酒劲吻你
借酒劲吻你 2020-12-17 09:43

I have a class like the below. GetInterfaces() says

If the current Type represents a type parameter in the definition of a generic type or generic

相关标签:
6条回答
  • 2020-12-17 10:10

    This is a nice piece from a duplicate question:

    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());
       }
    }
    

    And usage:

    foreach(Type ifc in typeof(Some).GetInterfaces(false)) {
       Console.WriteLine(ifc);
    }
    
    0 讨论(0)
  • 2020-12-17 10:18

    How about this for interface inheritance 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; }
        }
    
    0 讨论(0)
  • 2020-12-17 10:20

    The same MSDN page says

    The GetInterfaces method does not return interfaces in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which interfaces are returned, because that order varies.

    So no, you can't skip interfaces.

    0 讨论(0)
  • 2020-12-17 10:25

    As far as I can tell, none of the posted solutions work for typeof(C1) and typeof(I3) in the example below.

    I think the correct answer is that it is not possible to get the directly implemented interfaces using out-of-the-box framework calls.

    private interface I1 { }
    
    private interface I2 : I1 { }
    
    private interface I3 : I2, I1 { }
    
    public class C1 : I3, I1 { }
    
    0 讨论(0)
  • 2020-12-17 10:27

    This question is duplicated both here and here. In any case, here's my concise code that considers the points raised on this thread by @Ani and @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 讨论(0)
  • 2020-12-17 10:35

    Firstly, the MSDN snippet you've posted doesn't have anything to do with your actual question. It deals with when you have, for example, a generic type such as class Foo<T> where T : IEnumerable, and you try calling GetInterfaces on the type-parameter T, for example through typeof(Foo<>).GetGenericArguments().Single().GetInterfaces().

    Secondly, the problem is slightly ill-specified. Note that when a class implements an interface, it must implement all of the interfaces 'inherited' by that interface. It's simply a C# convenience feature that lets you omit the inherited interfaces in the class-declaration. In your example, it's perfectly legal (and no different) to explicitly include the 'inherited' GHI interface:

    class ABC : DEF, GHI {...}
    

    I've assumed that what you really want to do is find a 'minimal set' of interfaces that 'covers' all of the type's implemented interfaces. This results in a slightly simplified version of the Set cover problem.

    Here's one way to solve it, without any attempt whatsoever to be algorithmically efficient. The idea is to produce the minimal interface-set by filtering out those interfaces that are already implemented by other interfaces implemented by the type.

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

    ( EDIT - Here's a better way of doing the above:

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

    )

    For example, for 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
    

    Do note that this solution covers interface 'hierarchies' only (which is what you appear to want), not how they relate to the class's class hierarchy. In particular, it pays no attention to where in a class's hierarchy an interface was first implemented.

    For example, let's say we have:

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

    Now if you try using the solution I've described to get the minimal interface-set for Derived, you would get IBaz as well as IBar. If you don't want IBar, you would have to go to more effort: eliminate interfaces implemented by base-classes. The easiest way to do this would be to remove from the minimal interface-set those interfaces implemented by the class's immediate base-class, as is mentioned in @MikeEast's answer.

    0 讨论(0)
提交回复
热议问题