Testen Sie, ob das Objekt die Schnittstelle implementiert

355

Was ist der einfachste Weg zu testen, ob ein Objekt eine bestimmte Schnittstelle in C # implementiert? (Antwort auf diese Frage in Java )

JoshRivers
quelle

Antworten:

569
if (object is IBlah)

oder

IBlah myTest = originalObject as IBlah

if (myTest != null)
Robert C. Barth
quelle
85
+1 Die zweite ist besser, weil Sie wahrscheinlich später mit der ersten wirken müssen, wodurch Sie zwei Würfe erhalten ("ist" und dann eine explizite Besetzung). Beim zweiten Ansatz haben Sie nur einmal gewirkt.
Andrew Hare
51
@ Andrew: +1; Es ist wieder Zeit für den Link zum klassischen Double-Casting AntiPattern-Blogbeitrag von Julian M Bucknall .
Jeroen Wiert Pluimers
1
Bei der Optimierung werden Sie im ersten Fall wahrscheinlich nicht zweimal gecastet?
BuZz
1
@Joreen, dieser Link verfehlt einen Punkt, wenn Sie mit einer Struktur arbeiten, die Sie nicht als "as" verwenden können, da sie keine Null enthält, was das "as" versucht zurückzugeben. In diesem Fall müssen Sie eine Nullable durchlaufen Klasse wie int?, obwohl kein Problem, wenn Sie nur auf der Schnittstellenebene arbeiten, da es sich immer um Referenztypen handelt
MikeT
46
Seit C # 6.0:if (object is IBlah iblah) { iblah.SomeMethod(); }
Knelis
224

Die Verwendung der Operatoren isoder asist der richtige Weg, wenn Sie den Schnittstellentyp zur Kompilierungszeit kennen und über eine Instanz des zu testenden Typs verfügen. Etwas, das sonst niemand erwähnt zu haben scheint, ist Type.IsAssignableFrom:

if( typeof(IMyInterface).IsAssignableFrom(someOtherType) )
{
}

Ich denke, das ist viel ordentlicher als das Durchsehen des von zurückgegebenen Arrays GetInterfacesund hat den Vorteil, auch für Klassen zu arbeiten.

Andrew Kennan
quelle
Ich versuche festzustellen, ob ein Typ eine Instanziierung von IList implementiert. Ich verwende "typeof (IList <>). IsAssignableFrom (someType)", aber das funktioniert nicht.
KeyboardDrummer
3
Vielleicht ist es besser, dies in einer anderen Frage zu stellen. Wenn someType der Typ der Listenelemente ist, benötigen Sie möglicherweise typeof (IList <>). MakeGenericType (someType). Wenn someType der Listentyp ist, sollten Sie sich Type.GetGenericArguments und Type.GetGenericTypeDefinition ansehen.
Andrew Kennan
Ich benutze dies für die Typprüfung in einem Plugin-System. Es kann in Situationen verwendet werden, in denen eine Instanz des Objekts noch nicht vorhanden ist. Aber ich benutze sowohl diesen als auch Roberts Stil, je nachdem, was ich tue, habe ich in beide Richtungen abgestimmt.
James
Dies ist ein älterer Kommentar, aber um die Frage von @ Steenreem zu beantworten, verwenden Sie typeof(IList).IsAssignableFrom(someType), ohne die <>.
Saluce
Diese Methode funktioniert sogar mit Konvertierungsoperatoren und wenn TypeConverters beteiligt sind
Harald Coppoolse
22

Für die Instanz:

if (obj is IMyInterface) {}

Für die Klasse:

Überprüfen Sie, ob typeof(MyClass).GetInterfaces()die Schnittstelle enthalten ist.

Rauhotz
quelle
1
if (Array.IndexOf (typeof (MyClass) .GetInterfaces (), typeof (IMyInterface))! = -1) {...}
Constantin
2
oder: if (typeof (MyClass) .GetInterfaces (). Contains (typeof (IMyInterface))) {...}
Lance Fisher
17

Wenn Sie das typisierte Objekt nach der Prüfung verwenden möchten:
Seit C # 7.0:

if (obj is IMyInterface myObj)

Dies ist das gleiche wie

IMyInterface myObj = obj as IMyInterface;
if (myObj != null)

Siehe .NET-Dokumente: Musterübereinstimmung mit isMuster vom Typ #

Martin Schneider
quelle
16

Eine Variation von @ AndrewKennans Antwort, die ich kürzlich für zur Laufzeit erhaltene Typen verwendet habe:

if (serviceType.IsInstanceOfType(service))
{
    // 'service' does implement the 'serviceType' type
}
Berühmte Garkin
quelle
7

Dieser Beitrag ist eine gute Antwort.

public interface IMyInterface {}

public class MyType : IMyInterface {}

Dies ist ein einfaches Beispiel:

typeof(IMyInterface).IsAssignableFrom(typeof(MyType))

oder

typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
eliasetm
quelle
3

Zusätzlich zum Testen mit dem Operator "is" können Sie Ihre Methoden dekorieren, um sicherzustellen, dass an ihn übergebene Variablen eine bestimmte Schnittstelle implementieren, z. B.:

public static void BubbleSort<T>(ref IList<T> unsorted_list) where T : IComparable
{
     //Some bubbly sorting
}

Ich bin nicht sicher, in welcher Version von .Net dies implementiert wurde, sodass es in Ihrer Version möglicherweise nicht funktioniert.

Jamesmillerio
quelle
2
.net 2.0 hat Generika hinzugefügt.
Robert C. Barth
Dies ist die einzige Überprüfung zur Kompilierungszeit in diesem Thread, danke.
Dustin Malone
2

Was für mich funktioniert hat ist:

Assert.IsNotNull(typeof (YourClass).GetInterfaces().SingleOrDefault(i => i == typeof (ISomeInterface)));

Dutchman078
quelle
1

Kürzlich habe ich versucht, Andrew Kennans Antwort zu verwenden, und es hat aus irgendeinem Grund bei mir nicht funktioniert. Ich habe dies stattdessen verwendet und es hat funktioniert (Hinweis: Möglicherweise ist das Schreiben des Namespace erforderlich).

if (typeof(someObject).GetInterface("MyNamespace.IMyInterface") != null)
jahu
quelle
2
Wenn Sie diesen Weg gehen, bin ich kein Fan von magischen Strings, daher würde ich dies zumindest in typeof (IMyInterface) .Name anstelle von "MyNamespace.IMyInterface" ändern. Hilft dabei, den Refactoring-Beweis als Bonus zu benennen.
greyalien007
0

ich benutzte

Assert.IsTrue(myObject is ImyInterface);

für einen Test in meinem Unit-Test, der testet, dass myObject ein Objekt ist, das meine Schnittstelle ImyInterface implementiert hat.

iamrcw
quelle
-1

Ich hatte eine Situation, in der ich eine Variable an eine Methode übergab und nicht sicher war, ob es sich um eine Schnittstelle oder ein Objekt handeln würde.

Die Ziele waren:

  1. Wenn item eine Schnittstelle ist, instanziieren Sie ein Objekt basierend auf dieser Schnittstelle, wobei die Schnittstelle ein Parameter im Konstruktoraufruf ist.
  2. Wenn das Element ein Objekt ist, geben Sie eine Null zurück, da der Konstruktor für meine Aufrufe eine Schnittstelle erwartet und ich nicht wollte, dass der Code tankt.

Ich habe dies mit folgendem erreicht:

    if(!typeof(T).IsClass)
    {
       // If your constructor needs arguments...
       object[] args = new object[] { my_constructor_param };
       return (T)Activator.CreateInstance(typeof(T), args, null);
    }
    else
       return default(T);
Anthony Tristan
quelle
-12

Das sollte funktionieren :

MyInstace.GetType().GetInterfaces();

Aber auch schön:

if (obj is IMyInterface)

Oder sogar (nicht sehr elegant):

if (obj.GetType() == typeof(IMyInterface))
Yoann. B.
quelle
9
Die Überprüfung der Gleichheit mit typeof (IMyInterface) schlägt immer fehl. Abgestimmt.
Jay Bazuzi
Recht. Es gibt keine Instanzen einer Schnittstelle.
Rauhotz