2009-07-13 24 views
51

Załóżmy, że mam typ MyType. Chcę wykonać następujące czynności:Sprawdzanie, czy typ implementuje ogólny interfejs

  1. Sprawdzaj czy MyType implementuje IList interfejs jakiegoś T.
  2. Jeśli odpowiedź na (1) jest tak, dowiedzieć się, co T.

Wygląda na to, że jest to metoda GetInterface(), ale pozwala ona tylko na wyszukiwanie według określonej nazwy. Czy istnieje sposób, aby szukać „wszystkich interfejsów, które są z IList postaci”

pokrewne (Jeśli to możliwe chciałbym znów być również przydatna, jeśli to działało jeśli interfejs był podinterfejsu z IList.): How to determine if a type implements a specific generic interface type

Odpowiedz

80
// this conditional is necessary if myType can be an interface, 
// because an interface doesn't implement itself: for example, 
// typeof (IList<int>).GetInterfaces() does not contain IList<int>! 
if (myType.IsInterface && myType.IsGenericType && 
    myType.GetGenericTypeDefinition() == typeof (IList<>)) 
    return myType.GetGenericArguments()[0] ; 

foreach (var i in myType.GetInterfaces()) 
    if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof (IList<>)) 
     return i.GetGenericArguments()[0] ; 

Edit: Nawet jeśli myType realizuje IDerivedFromList<> ale nie bezpośrednio, IList<>IList<> będzie pojawi się w tablicy zwróconej przez GetInterfaces().

Aktualizacja: dodano sprawdzenie dla przypadku krawędzi, gdzie myType jest ogólnym interfejsem, o którym mowa.

+0

Obsługuje także przypadek tablic, co jest miłe. Jeśli chcesz przetestować jawnie tablice, użyj "if (myType.IsArray) return myType.GetElementType();" (Chociaż może to być szybsze, mam nadzieję, że nic z tego nie jest krytyczne pod względem wydajności!) – yoyo

+0

Dla osób takich jak ja, które były ciekawi, dlaczego potrzebne jest .IsInterface: GetGenericTypeDefinition() wyrzuca, jeśli jest wywoływany w typie nietypowym. – GameFreak

+0

Właściwość Type.IsGenericType nie jest dostępna w sieciach o jakości 1.6 i niższych (a zatem niedostępnych w .NET Core 1.0), ale można użyć TypeInfo.IsGenericType zamiast: type.GetTypeInfo(). IsGenericType. – dotarj

0

Jeśli prawidłowo rozumiem twoje pytanie, to jest to, co próbujesz zrobić. Jeśli nie, proszę wyjaśnić dalej.

public class MyType : ISomeInterface 
{ 
} 

MyType o = new MyType(); 

if(o is ISomeInterface) 
{ 
} 

edit: jeśli zmienić zapytanie, należy dodać fakt, że edited..because teraz moja odpowiedź wygląda jakby nie należą.

W tym przypadku, jest tu bardzo duża LINQ

  var item = typeof(MyType).GetInterfaces() 
          .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>)) 
          .Select(t => t.GetGenericArguments().First()) 
          .FirstOrDefault(); 

if(item != null) 
//it has a type 
11

użyciu odbicia (a niektóre LINQ) można łatwo to zrobić:

public static IEnumerable<Type> GetIListTypeParameters(Type type) 
{ 
    // Query. 
    return 
     from interfaceType in type.GetInterfaces() 
     where interfaceType.IsGenericType 
     let baseInterface = interfaceType.GetGenericTypeDefinition() 
     where baseInterface == typeof(IList<>) 
     select interfaceType.GetGenericArguments().First(); 
} 

Po pierwsze, są coraz interfejsy od rodzaju i odfiltrowanie tylko dla tych, które są typu rodzajowego.

Następnie otrzymasz ogólną definicję typów dla tych typów interfejsów i sprawdź, czy jest taka sama jak IList<>.

Stamtąd wystarczy pobrać ogólne argumenty dla oryginalnego interfejsu.

Pamiętaj, że typ może mieć wiele implementacji IList<T>, dlatego zwracana jest nazwa IEnumerable<Type>.

+0

Jeśli zawiniesz wyrażenie zwrotne w nawiasach i dodasz kolejny ".First()" do końca, to zwróci Typ zamiast długości-1 IZlicza , co jest nieco łatwiejsze w obsłudze. (Osobiście uważam, że jest to przykład bycia zbyt sprytnym z LINQ, ale może to tylko ja.) – yoyo

+0

@yoyo Lub możesz po prostu zadzwonić "Pierwszy" na temat wyników tej metody. Jeśli zwrócisz 'First' z tej metody, to * zakładasz * jeden parametr, który jest wprost * zły *. – casperOne

+0

Dobra rada @ casperOne, MyType OP może wdrożyć IList i IList . Pytanie powinno więc brzmieć: "znaleźć T", a nie "znaleźć T". Przyjęta odpowiedź również tego nie dotyczy. – yoyo

1

jako rozszerzenie metody pomocnika

public static bool Implements<I>(this Type type, I @interface) where I : class 
{ 
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface) 
     throw new ArgumentException("Only interfaces can be 'implemented'."); 

    return (@interface as Type).IsAssignableFrom(type); 
} 

przykład użycia:

var testObject = new Dictionary<int, object>(); 
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true! 
4
public static bool Implements<I>(this Type type) where I : class 
    { 
     if (!typeof(I).IsInterface) 
     { 
      throw new ArgumentException("Only interfaces can be 'implemented'."); 
     } 

     return typeof(I).IsAssignableFrom(type); 
    } 
1

Korzystanie propozycję Antona Tykhyy, oto jest małą metodę rozszerzenia, aby sprawdzić, czy jakiś rodzaj implementuje rodzajowy interfejs jeden podany rodzaj parametrów ogólnych:

public static class ExtensionMethods 
{ 
    /// <summary> 
    /// Checks if a type has a generic interface. 
    /// For example 
    ///  mytype.HasGenericInterface(typeof(IList<>), typeof(int)) 
    /// will return TRUE if mytype implements IList<int> 
    /// </summary> 
    public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter) 
    { 
     foreach (Type i in type.GetInterfaces()) 
      if (i.IsGenericType && i.GetGenericTypeDefinition() == interf) 
       if (i.GetGenericArguments()[0] == typeparameter) 
        return true; 

     return false; 
    } 
} 
Powiązane problemy