Gegen Internetzensur
Stoppt die Vorratsdatenspeicherung! Jetzt klicken & handeln!Willst du auch bei der Aktion teilnehmen? Hier findest du alle relevanten Infos und Materialien:
  • Flickr Photos

    www.flickr.com
17. Mai
Sam

C# Code Snippet: Testen, ob ein Typ ein bestimmtes Interface implementiert

Manchmal möchte man testen, ob ein (erst) zur Laufzeit bekanntes Objekt ein bestimmtes Interface implementiert. Die Type-Klasse bietet hierfür die Funktion FindInterfaces(), die allerdings unter Umständen etwas mehr Overhead darstellt, als eigentlich nötig ist. Wenn man das Problem häufiger hat, ist hier ein Ansatz, um den Aufwand zu verringern. Es ist eine Implementierung als Extension Method und setzt daher Framework 3.5 oder einen kleinen Kniff voraus; Es ist allerdings auch nicht weiter schwierig, es als normale, statische Funktion zu implementieren – einfach das this in der Parameterliste entfernen.

  1. [DebuggerStepThrough]
  2. public static bool HasInterface(this Type type, Type interfaceType)
  3. {
  4.     Type[] array = type.FindInterfaces(
  5.         delegate(Type typeObj, Object criteriaObj)
  6.         {
  7.             return typeObj.Equals((Type)criteriaObj);
  8.         },
  9.         interfaceType
  10.     );
  11.     return array.Length > 0;
  12. }

Beispiel zur Anwendung:

  1. // als Extension Method
  2. bool hasInterface = myVariable.GetType().HasInterface(typeof(ISomeInterface));
  3.  
  4. // als normale, statische Methode
  5. bool hasInterface = HasInterface(myVariable.GetType(), typeof(ISomeInterface));

Der Vergleich wird platzsparend in Form einer anonymen Funktion (die delegate) durchgeführt, das [DebuggerStepThrough]-Attribut sorgt dafür, dass der Debugger die Funktion nicht besucht, wenn man Step Into benutzt – spart Zeit und Nerven.

Nachtrag: Will man testen, ob eine Klasse ein bestimmtes, generisches Interface implementiert, ohne dass man den genauen Typparameter kennt oder benennen will, ist die Funktion in ihrer derzeitigen Form ungeeignet. Der Grund: typeof(IList<>) liefert eine Typdefinition, während typeof(IList<int>) einen Typ liefert – Equals schlägt fehl.

Folgende Beobachtung schafft Abhilfe:

  1. bool test1_1 = typeof(IList< int >).IsGenericType; // true
  2. bool test1_2 = typeof(IList< int >).IsGenericTypeDefinition; // false
  3.  
  4. bool test2_1 = typeof(IList<>).IsGenericType; // true
  5. bool test2_2 = typeof(IList<>).IsGenericTypeDefinition; // true

Mit einer kleinen Änderung klappt dann alles:

  1. [DebuggerStepThrough]
  2. public static bool HasInterface(this Type type, Type interfaceType)
  3. {
  4.     Type[] array = type.FindInterfaces(
  5.         delegate(Type typeObj, Object criteriaObj)
  6.         {
  7.             // wenn das Typobjekt generisch ist, aber keine Definition (denn ansonsten greift Equals bereits zu)
  8.             // und wenn das Vergleichsobjekt eine Typdefinition ist …
  9.             if (typeObj.IsGenericType && !typeObj.IsGenericTypeDefinition && ((Type)criteriaObj).IsGenericTypeDefinition)
  10.                         // … dann holen wir uns die Typdefinition des Objektes und vergleichen damit
  11.                         return (typeObj.GetGenericTypeDefinition().Equals(criteriaObj));
  12.             return typeObj.Equals((Type)criteriaObj);
  13.         },
  14.         interfaceType
  15.     );
  16.     return array.Length > 0;
  17. }

Voilá.

2 Antworten zu „C# Code Snippet: Testen, ob ein Typ ein bestimmtes Interface implementiert”

  1. #1~Fabse

    Reicht dir der “is”-Operator nicht aus?

    Object bb = new Bullet(new Vector2(), 500, 0);
    if(bb is IParticle)
    {
    //bb implementiert IParticle
    }

    in meinem Fall implementiert Bullet IParticle. Wenn ich als Datentyp Bullet statt Object nehme, meint Resharper sogar, dass das IF immer true wird!

  2. #2~mac

    Jap, vollkommen richtig! Ich mach’s auch genau so. :mrgreen:

    Das Problem mit den generischen Interfaces bleibt allerdings; Ich brauchte das für eine Serialisierungsfunktion, die Listen oder Dictionaries (IDictionary< ,>) gesondert behandelt; Leider kann man diese Typdefinitionen nicht per “is” abgreifen.