Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Ceci est une erreur. L'opérateur typeof en C # ne peut prendre que des noms de type, pas des objets.
if (obj1.GetType() == typeof(int))
// Some code here
Cela fonctionnera, mais peut-être pas comme prévu. Pour les types de valeur, comme vous l'avez montré ici, c'est acceptable, mais pour les types de référence, cela ne retournerait vrai que si le type était exactement le même type, pas autre chose dans la hiérarchie d'héritage. Par exemple:
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");
}
Cela s'imprimerait "o is something else"
, car le type de o
est Dog
non Animal
. Vous pouvez cependant faire ce travail si vous utilisez la IsAssignableFrom
méthode de la Type
classe.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Cette technique reste cependant un problème majeur. Si votre variable est nulle, l'appel à GetType()
lèvera une exception NullReferenceException. Donc, pour le faire fonctionner correctement, vous feriez:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Avec cela, vous avez un comportement équivalent du is
mot - clé. Par conséquent, si tel est le comportement que vous souhaitez, vous devez utiliser le is
mot - clé, qui est plus lisible et plus efficace.
if(o is Animal)
Console.WriteLine("o is an animal");
Dans la plupart des cas, cependant, le is
mot - clé n'est toujours pas ce que vous voulez vraiment, car il ne suffit généralement pas de savoir qu'un objet est d'un certain type. Habituellement, vous souhaitez réellement utiliser cet objet en tant qu'instance de ce type, ce qui nécessite également de le convertir. Et vous pouvez donc vous retrouver à écrire du code comme ceci:
if(o is Animal)
((Animal)o).Speak();
Mais cela oblige le CLR à vérifier le type de l'objet jusqu'à deux fois. Il le vérifiera une fois pour satisfaire l' is
opérateur, et s'il o
s'agit bien d'un Animal
, on le refait vérifier pour valider le cast.
Il est plus efficace de le faire à la place:
Animal a = o as Animal;
if(a != null)
a.Speak();
L' as
opérateur est un transtypage qui ne lèvera pas d'exception s'il échoue, au lieu de cela null
. De cette façon, le CLR vérifie le type de l'objet une seule fois, et après cela, nous avons juste besoin de faire une vérification nulle, ce qui est plus efficace.
Mais attention: beaucoup de gens tombent dans un piège avec as
. Parce qu'il ne lève pas d'exceptions, certaines personnes le considèrent comme un casting "sûr", et ils l'utilisent exclusivement, évitant les lancers réguliers. Cela conduit à des erreurs comme celle-ci:
(o as Animal).Speak();
Dans ce cas, le développeur suppose clairement que ce o
sera toujours un Animal
, et tant que leur hypothèse est correcte, tout fonctionne bien. Mais s'ils se trompent, ce qu'ils obtiennent ici est un NullReferenceException
. Avec un casting régulier, ils auraient obtenu un à la InvalidCastException
place, ce qui aurait identifié plus correctement le problème.
Parfois, ce bug peut être difficile à trouver:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
C'est un autre cas où le développeur s'attend clairement o
à être à Animal
chaque fois, mais ce n'est pas évident dans le constructeur, où la as
distribution est utilisée. Ce n'est pas évident jusqu'à ce que vous arriviez à la Interact
méthode, où le animal
champ devrait être attribué positivement. Dans ce cas, non seulement vous vous retrouvez avec une exception trompeuse, mais elle n'est levée que bien plus tard que lorsque l'erreur réelle s'est produite.
En résumé:
Si vous avez seulement besoin de savoir si un objet est d'un certain type, utilisez is
.
Si vous devez traiter un objet comme une instance d'un certain type, mais vous ne savez pas avec certitude si l'objet sera de ce type, utilisez-le as
et vérifiez-le null
.
Si vous devez traiter un objet comme une instance d'un certain type, et que l'objet est censé être de ce type, utilisez une conversion régulière.
as
!