Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Isto é um erro. O operador typeof em C # pode usar apenas nomes de tipos, não objetos.
if (obj1.GetType() == typeof(int))
// Some code here
Isso funcionará, mas talvez não como você esperaria. Para os tipos de valor, como você mostrou aqui, é aceitável, mas para os tipos de referência, ele só retornará true se o tipo for exatamente o mesmo tipo, e não outra coisa na hierarquia de herança. Por exemplo:
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");
}
Isso imprimiria "o is something else", porque o tipo de oé Dog, não Animal. Você pode fazer isso funcionar, no entanto, se você usar o IsAssignableFrommétodo da Typeclasse.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Essa técnica ainda deixa um grande problema, no entanto. Se sua variável for nula, a chamada para GetType()lançará uma NullReferenceException. Então, para fazê-lo funcionar corretamente, você faria:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
Com isso, você tem um comportamento equivalente à ispalavra - chave. Portanto, se esse é o comportamento que você deseja, use a ispalavra - chave, que é mais legível e mais eficiente.
if(o is Animal)
Console.WriteLine("o is an animal");
Na maioria dos casos, porém, a ispalavra - chave ainda não é o que você realmente deseja, porque geralmente não é suficiente apenas saber que um objeto é de um determinado tipo. Geralmente, você deseja realmente usar esse objeto como uma instância desse tipo, o que exige a conversão também. E assim, você pode escrever código como este:
if(o is Animal)
((Animal)o).Speak();
Mas isso faz com que o CLR verifique o tipo do objeto até duas vezes. Ele irá checá-lo uma vez para satisfazer o isoperador e, se ofor de fato um Animal, fazemos novamente o checagem para validar o elenco.
É mais eficiente fazer isso:
Animal a = o as Animal;
if(a != null)
a.Speak();
O asoperador é um elenco que não emitirá uma exceção se falhar, retornando null. Dessa forma, o CLR verifica o tipo de objeto apenas uma vez e, depois disso, precisamos fazer uma verificação nula, que é mais eficiente.
Mas cuidado: muitas pessoas caem em uma armadilha as. Como não gera exceções, algumas pessoas pensam nele como um elenco "seguro" e o usam exclusivamente, evitando os lançamentos regulares. Isso leva a erros como este:
(o as Animal).Speak();
Neste caso, o desenvolvedor está assumindo claramente que oirá sempre ser uma Animal, e desde que a sua hipótese é correta, tudo funciona bem. Mas se eles estão errados, então o que eles acabam com aqui é um NullReferenceException. Com um elenco regular, eles teriam conseguido um InvalidCastExceptionlugar, o que teria identificado mais corretamente o problema.
Às vezes, esse bug pode ser difícil de encontrar:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Este é outro caso em que o desenvolvedor espera claramente oestar Animalsempre, mas isso não é óbvio no construtor, onde o aselenco é usado. Não é óbvio até que você chegue ao Interactmétodo, onde animalse espera que o campo seja atribuído positivamente. Nesse caso, você não apenas acaba com uma exceção enganosa, mas é lançada até potencialmente muito mais tarde do que quando ocorreu o erro real.
Em suma:
Se você só precisa saber se um objeto é ou não de algum tipo, use is.
Se você precisar tratar um objeto como uma instância de um determinado tipo, mas não tiver certeza de que o objeto será desse tipo, use ase verifique null.
Se você precisar tratar um objeto como uma instância de um determinado tipo, e o objeto for desse tipo, use uma conversão regular.
as!