Pytanie Masz tylko bezpośredni interfejs zamiast wszystkich?


Mam klasę podobną do poniższej. GetInterfaces () mówi

Jeśli bieżący typ reprezentuje typ   parametr w definicji a   rodzaj ogólny lub metoda ogólna, to   metoda przeszukuje interfejs   ograniczenia i dowolne interfejsy   odziedziczone po klasie lub interfejsie   ograniczenia.

Czy mogę nie uzyskać żadnego odziedziczonego interfejsu? Kiedy używam GetInterfaces na ABC, chcę tylko zobaczyć DEF, a nie DEF i GHI.

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

18
2018-03-15 22:07


pochodzenie


Odkąd jam only on my iPad I cant przetestuj kod lub wyszukaj wszystkie metody, ale tutajs a thought. Could you find all the interfaces your type implements (including inherites ones), then move on to the base type of your type, find all the interfaces *that* type implements, and subtract those from the first set? I would think you would be left with what ABC itself added of interfaces. If anyone wants to "steal" this comment and type up a real answer of it, please do, it wonByć do jutra, aż wrócę do mojego komputera. - Lasse Vågsæther Karlsen
GetInterfaces () jest metodą na klasie Type. - Roman Royter
Ach, moje przeprosiny, twój "typ podstawowy" to interfejs, więc nie wiem. - Lasse Vågsæther Karlsen
@Lasse: Różnie rozumiałem ten problem; Uważam, że PO jest zainteresowany tylko hierarchiami interfejsu. - Ani


Odpowiedzi:


Po pierwsze, opublikowany fragment kodu MSDN nie ma nic wspólnego z rzeczywistym pytaniem. Zajmuje się, gdy masz na przykład typ ogólny, taki jak class Foo<T> where T : IEnumerablei próbujesz dzwonić GetInterfaces na parametrze typu T, na przykład przez typeof(Foo<>).GetGenericArguments().Single().GetInterfaces(). 

Po drugie, problem jest trochę źle określony. Zwróć uwagę, że gdy klasa implementuje interfejs, musi implementować wszystko interfejsów "odziedziczonych" przez ten interfejs. Jest to po prostu wygodna funkcja C #, która pozwala pominąć odziedziczone interfejsy w deklaracji klasy. W twoim przykładzie jest to całkowicie legalne (i nie różni się) wyraźnie obejmują "odziedziczony" GHI berło:

class ABC : DEF, GHI {...}

Założę się, że to, co naprawdę chcesz zrobić, to znaleźć "minimalny zestaw" interfejsów, który "obejmuje" wszystkie zaimplementowane interfejsy tego typu. Powoduje to nieznacznie uproszczoną wersję Ustaw problem z pokrywą.

Oto jeden sposób, aby go rozwiązać, bez jakiejkolwiek próby efektywnego algorytmicznie. Pomysł polega na stworzeniu minimalnego zestawu interfejsów poprzez odfiltrowanie tych interfejsów, które są już wprowadzony przez inny interfejsy implementowane przez typ.

Type type = ...

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

( EDYTOWAĆ - Oto lepszy sposób na wykonanie powyższych czynności:

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

)

Na przykład dla 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

Zauważ, że to rozwiązanie obejmuje berło tylko "hierarchie" (to jest to, czego oczekujesz), a nie jak odnoszą się do klasy klasa hierarchia. W szczególności nie zwraca na to uwagi gdzie w hierarchii klas najpierw zaimplementowano interfejs.

Załóżmy na przykład, że mamy:

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

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

Teraz, jeśli spróbujesz użyć rozwiązania, które opisałem, aby uzyskać minimalny zestaw interfejsów Derived, dostaniesz IBaz jak również IBar. Jeśli nie chcesz IBar, będziesz musiał podjąć więcej wysiłku: wyeliminuj interfejsy implementowane przez klasy bazowe. Najprościej to zrobić, usuwając z interfejsu minimalnego interfejsy zaimplementowane przez bezpośrednią klasę klasy klasy, jak wspomniano w odpowiedzi @ MikeEast'a.


27
2018-03-15 22:20



+1 miły i działa dla interfejsów - BrokenGlass
Doskonała odpowiedź.


To jest fajny kawałek z duplikat pytania:

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

I użycie:

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

3
2018-03-15 22:33



Problem z tym, że nie zadziała, np. IList<string>Miałem podobne rozwiązanie oparte na komentarzu @ Lasse - BrokenGlass
Ach, dla BaseType rzecz. Nie widziałem tego. - Mikael Östberg


Ta sama strona MSDN mówi

Metoda GetInterfaces tego nie robi   zwrócić interfejsy w szczególności   porządek, taki jak alfabetyczny lub   kolejność deklaracji. Twój kod nie może   zależą od kolejności, w jakiej   interfejsy są zwracane, ponieważ to   kolejność jest różna.

Więc nie, nie można pominąć interfejsów.


0
2018-03-15 22:12



OP nie próbuje pomijać interfejsów, ale pobiera tylko bezpośrednio zaimplementowane interfejsy. - Marcelo Cantos
Myślę, że głównym problemem jest to, że gdy typ implementuje interfejs, istniejes no concept of "directly implemented" any more. YouMuszę przeanalizować wykres "dziedziczenia" interfejsu i znaleźć najbardziej prawdopodobny wynik. - Lasse Vågsæther Karlsen


A co powiesz na dziedziczenie dziedziczenia interfejsu?

    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
2018-05-31 13:53





To pytanie jest powielone zarówno tutaj i tutaj. W każdym razie oto mój zwięzły kod, który uwzględnia punkty podniesione w tym wątku przez @Ani i @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
2017-09-06 18:36