Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Dies ist ein Fehler. Der Operator typeof in C # kann nur Typnamen annehmen, keine Objekte.
if (obj1.GetType() == typeof(int))
// Some code here
Dies wird funktionieren, aber vielleicht nicht so, wie Sie es erwarten würden. Wie Sie hier gezeigt haben, ist dies für Werttypen akzeptabel. Für Referenztypen wird jedoch nur true zurückgegeben, wenn der Typ genau derselbe Typ ist und nicht etwas anderes in der Vererbungshierarchie. Zum Beispiel:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
Dies würde drucken "o is something else"
, weil die Art der o
ist Dog
, nicht Animal
. Sie können dies jedoch zum Laufen bringen, wenn Sie die IsAssignableFrom
Methode der Type
Klasse verwenden.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Diese Technik hinterlässt jedoch immer noch ein großes Problem. Wenn Ihre Variable null ist, GetType()
löst der Aufruf von eine NullReferenceException aus. Damit es richtig funktioniert, müssen Sie Folgendes tun:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Damit haben Sie ein gleichwertiges Verhalten des is
Schlüsselworts. Wenn dies das gewünschte Verhalten ist, sollten Sie daher das is
Schlüsselwort verwenden, das lesbarer und effizienter ist.
if(o is Animal)
Console.WriteLine("o is an animal");
In den meisten Fällen ist das is
Schlüsselwort jedoch immer noch nicht das, was Sie wirklich wollen, da es normalerweise nicht ausreicht, nur zu wissen, dass ein Objekt von einem bestimmten Typ ist. Normalerweise wollen Sie tatsächlich nutzen das Objekt als Instanz dieses Typs, die es auch erfordert Gießen. Und so können Sie feststellen, dass Sie Code wie folgt schreiben:
if(o is Animal)
((Animal)o).Speak();
Dadurch überprüft die CLR den Objekttyp bis zu zweimal. Es wird einmal überprüft, um den is
Bediener zufrieden zu stellen , und wenn dies o
tatsächlich der Animal
Fall ist, wird es erneut überprüft, um die Besetzung zu validieren.
Es ist effizienter, dies stattdessen zu tun:
Animal a = o as Animal;
if(a != null)
a.Speak();
Der as
Operator ist eine Besetzung, die keine Ausnahme auslöst, wenn sie fehlschlägt, sondern zurückkehrt null
. Auf diese Weise überprüft die CLR den Objekttyp nur einmal, und danach müssen wir nur noch eine Nullprüfung durchführen, was effizienter ist.
Aber Vorsicht: Viele Menschen geraten mit in eine Falle as
. Da es keine Ausnahmen gibt, betrachten einige Leute es als "sichere" Besetzung, und sie verwenden es ausschließlich und meiden reguläre Besetzungen. Dies führt zu solchen Fehlern:
(o as Animal).Speak();
In diesem Fall wird der Entwickler deutlich unter der Annahme , dass o
wird immer eine sein Animal
, und solange ihre Annahme richtig ist, funktioniert alles einwandfrei. Aber wenn sie falsch liegen, dann ist das, was sie hier haben, ein NullReferenceException
. Mit einer regulären Besetzung hätten sie InvalidCastException
stattdessen eine bekommen , die das Problem genauer identifiziert hätte.
Manchmal ist dieser Fehler schwer zu finden:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Dies ist ein weiterer Fall, in dem der Entwickler eindeutig erwartet o
, dass dies Animal
jedes Mal der Fall ist. Dies ist jedoch im Konstruktor, in dem die as
Besetzung verwendet wird, nicht offensichtlich . Es ist nicht offensichtlich, bis Sie zu der Interact
Methode gelangen, bei der animal
erwartet wird, dass das Feld positiv zugewiesen wird. In diesem Fall kommt es nicht nur zu einer irreführenden Ausnahme, sondern sie wird erst viel später ausgelöst, als der eigentliche Fehler aufgetreten ist.
Zusammenfassend:
Wenn Sie nur wissen müssen, ob ein Objekt von einem Typ ist oder nicht, verwenden Sie is
.
Wenn Sie ein Objekt als Instanz eines bestimmten Typs behandeln müssen, aber nicht sicher sind, ob das Objekt von diesem Typ ist, verwenden Sie es as
und suchen Sie nach null
.
Wenn Sie ein Objekt als Instanz eines bestimmten Typs behandeln müssen und das Objekt von diesem Typ sein soll, verwenden Sie eine reguläre Besetzung.
as
!