Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Esto es un error El operador typeof en C # solo puede tomar nombres de tipos, no objetos.
if (obj1.GetType() == typeof(int))
// Some code here
Esto funcionará, pero quizás no como era de esperar. Para los tipos de valor, como ha mostrado aquí, es aceptable, pero para los tipos de referencia, solo devolvería verdadero si el tipo era exactamente el mismo tipo, no otra cosa en la jerarquía de herencia. Por ejemplo:
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");
}
Esto se imprimiría "o is something else", porque el tipo de oes Dog, no Animal. Sin embargo, puede hacer que esto funcione si usa el IsAssignableFrommétodo de la Typeclase.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Sin embargo, esta técnica aún deja un gran problema. Si su variable es nula, la llamada a GetType()arrojará una NullReferenceException. Entonces, para que funcione correctamente, harías:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Con esto, tiene un comportamiento equivalente de la ispalabra clave. Por lo tanto, si este es el comportamiento que desea, debe usar la ispalabra clave, que es más legible y más eficiente.
if(o is Animal)
Console.WriteLine("o is an animal");
Sin embargo, en la mayoría de los casos, la ispalabra clave todavía no es lo que realmente desea, porque generalmente no es suficiente saber que un objeto es de cierto tipo. Por lo general, desea utilizar ese objeto como una instancia de ese tipo, que también requiere lanzarlo. Y entonces puede que te encuentres escribiendo código como este:
if(o is Animal)
((Animal)o).Speak();
Pero eso hace que el CLR verifique el tipo de objeto hasta dos veces. Lo verificará una vez para satisfacer al isoperador, y si de ohecho es un Animal, lo haremos verificar nuevamente para validar el lanzamiento.
Es más eficiente hacer esto en su lugar:
Animal a = o as Animal;
if(a != null)
a.Speak();
El asoperador es un elenco que no lanzará una excepción si falla, sino que regresará null. De esta manera, el CLR verifica el tipo de objeto solo una vez, y después de eso, solo necesitamos hacer una verificación nula, que es más eficiente.
Pero cuidado: muchas personas caen en una trampa con as. Debido a que no arroja excepciones, algunas personas lo consideran un yeso "seguro", y lo usan exclusivamente, evitando los lanzamientos regulares. Esto lleva a errores como este:
(o as Animal).Speak();
En este caso, el desarrollador está asumiendo claramente que ohabrá siempre ser una Animal, y siempre que su suposición es correcta, todo funciona bien. Pero si están equivocados, entonces lo que terminan aquí es a NullReferenceException. Con un reparto regular, habrían obtenido un InvalidCastExceptionen su lugar, que habría identificado más correctamente el problema.
A veces, este error puede ser difícil de encontrar:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Este es otro caso en el que el desarrollador claramente espera oserlo Animalcada vez, pero esto no es obvio en el constructor, donde asse usa el elenco. No es obvio hasta que llegue al Interactmétodo, donde animalse espera que el campo se asigne positivamente. En este caso, no solo termina con una excepción engañosa, sino que no se produce hasta potencialmente mucho más tarde que cuando ocurrió el error real.
En resumen:
Si solo necesita saber si un objeto es o no de algún tipo, úselo is.
Si necesita tratar un objeto como una instancia de cierto tipo, pero no está seguro de que el objeto sea de ese tipo, utilícelo asy verifique null.
Si necesita tratar un objeto como una instancia de cierto tipo, y se supone que el objeto es de ese tipo, use un molde regular.
as!