Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Hier liegt ein Fehler vor. Der typeof-Operator in C# kann nur Typnamen annehmen, keine Objekte.
if (obj1.GetType() == typeof(int))
// Some code here
Das wird funktionieren, aber vielleicht nicht so, wie Sie es erwarten würden. Für Werttypen, wie Sie hier gezeigt haben, ist es akzeptabel, aber für Referenztypen würde es nur true zurückgeben, wenn der Typ der genau dasselbe Typ, 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 Folgendes drucken "o is something else"
weil die Art der o
es Dog
, nicht Animal
. Sie können dies jedoch bewerkstelligen, wenn Sie die IsAssignableFrom
Methode der Type
Klasse.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Diese Technik birgt jedoch noch ein großes Problem. Wenn Ihre Variable null ist, wird der Aufruf von GetType()
wird eine NullReferenceException auslösen. Damit es richtig funktioniert, müssen Sie also Folgendes tun:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Damit haben Sie ein gleichwertiges Verhalten der is
Schlüsselwort. Wenn Sie dieses Verhalten wünschen, sollten Sie daher das is
Schlüsselwort, das besser lesbar und effizienter ist.
if(o is Animal)
Console.WriteLine("o is an animal");
In den meisten Fällen ist jedoch die is
Schlüsselwort ist immer noch nicht das, was Sie wirklich wollen, denn es reicht normalerweise nicht aus, nur zu wissen, dass ein Objekt von einem bestimmten Typ ist. Normalerweise wollen Sie tatsächlich verwenden. dieses Objekt als eine Instanz dieses Typs, was ebenfalls ein Casting erfordert. Und so kann es passieren, dass Sie Code wie diesen schreiben:
if(o is Animal)
((Animal)o).Speak();
Dies führt jedoch dazu, dass die CLR den Typ des Objekts bis zu zwei Mal überprüft. Sie wird ihn einmal prüfen, um die is
Operator, und wenn o
ist in der Tat ein Animal
lassen wir es noch einmal überprüfen, um die Besetzung zu bestätigen.
Es ist effizienter, dies stattdessen zu tun:
Animal a = o as Animal;
if(a != null)
a.Speak();
El as
Operator ist ein Cast, der keine Ausnahme auslöst, wenn er fehlschlägt, sondern stattdessen eine null
. Auf diese Weise überprüft die CLR den Typ des Objekts nur einmal, und danach müssen wir nur noch eine Nullprüfung durchführen, was effizienter ist.
Aber Vorsicht: Viele Menschen tappen in eine Falle mit as
. Da er keine Ausnahmen auslöst, halten ihn manche Leute für einen "sicheren" Cast und verwenden ihn ausschließlich, während sie normale Casts meiden. Dies führt zu Fehlern wie diesem:
(o as Animal).Speak();
In diesem Fall geht der Entwickler eindeutig davon aus, dass o
wird immer ein sein Animal
und solange ihre Annahme richtig ist, funktioniert alles gut. Aber wenn sie sich irren, dann ist das, was sie hier am Ende haben, eine NullReferenceException
. Mit einer normalen Besetzung hätten sie eine InvalidCastException
was das Problem besser erkannt hätte.
Manchmal kann dieser Fehler schwer zu finden sein:
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, dass o
zu sein Animal
jedes Mal, aber das ist nicht offensichtlich im Konstruktor, wo die as
Guss verwendet wird. Es ist nicht offensichtlich, bis man zu dem Interact
Methode, bei der die animal
Es wird erwartet, dass das Feld positiv belegt wird. In diesem Fall kommt es nicht nur zu einer irreführenden Ausnahme, sondern sie wird auch erst viel später ausgelöst, als der eigentliche Fehler aufgetreten ist.
Zusammengefasst:
-
Wenn Sie nur wissen müssen, ob ein Objekt von einem bestimmten Typ ist oder nicht, verwenden Sie is
.
-
Wenn Sie ein Objekt als Instanz eines bestimmten Typs behandeln müssen, aber nicht sicher wissen, dass das Objekt von diesem Typ sein wird, verwenden Sie as
und prüfen auf null
.
-
Wenn Sie ein Objekt als Instanz eines bestimmten Typs behandeln müssen, und das Objekt soll von diesem Typ sein, verwenden Sie einen regulären Cast.