Respostas:
Isso deve responder a essa pergunta e mais algumas.
A segunda linha if (obj.GetType() == typeof(ClassA)) {}
,, é mais rápida, para aqueles que não querem ler o artigo.
(Esteja ciente de que eles não fazem a mesma coisa)
typeof(string).TypeHandle
com a ldtoken
instrução CIL, mas parece que o CLR cuida disso no JIT. Ainda são necessários alguns códigos de operação extras, mas é uma aplicação mais generalizada da otimização.
GetType
, is
é sempre uma escolha mais segura no que diz respeito ao desempenho. Claro que eles fazem coisas diferentes.
object obj;
variável, ela já não está encaixotada quando isso tende a ser testado? Existe um caso em que você precisa testar o tipo de algo e ele ainda não está na caixa como um objeto?
Importa o que é mais rápido, se eles não fazem a mesma coisa? Comparar o desempenho de declarações com diferentes significados parece uma má ideia.
is
informa se o objeto implementa ClassA
em qualquer lugar da hierarquia de tipos. GetType()
informa sobre o tipo mais derivado.
Não é a mesma coisa.
Eles não fazem a mesma coisa. O primeiro funciona se obj for do tipo ClassA ou de alguma subclasse da ClassA. O segundo corresponderá apenas a objetos do tipo ClassA. O segundo será mais rápido, pois não precisa verificar a hierarquia de classes.
Para quem quer saber o motivo, mas não quer ler o artigo mencionado em é vs typeof .
Fiz alguns testes comparativos onde eles fazem os mesmos tipos selados.
var c1 = "";
var c2 = typeof(string);
object oc1 = c1;
object oc2 = c2;
var s1 = 0;
var s2 = '.';
object os1 = s1;
object os2 = s2;
bool b = false;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
b = c1.GetType() == typeof(string); // ~60ms
b = c1 is string; // ~60ms
b = c2.GetType() == typeof(string); // ~60ms
b = c2 is string; // ~50ms
b = oc1.GetType() == typeof(string); // ~60ms
b = oc1 is string; // ~68ms
b = oc2.GetType() == typeof(string); // ~60ms
b = oc2 is string; // ~64ms
b = s1.GetType() == typeof(int); // ~130ms
b = s1 is int; // ~50ms
b = s2.GetType() == typeof(int); // ~140ms
b = s2 is int; // ~50ms
b = os1.GetType() == typeof(int); // ~60ms
b = os1 is int; // ~74ms
b = os2.GetType() == typeof(int); // ~60ms
b = os2 is int; // ~68ms
b = GetType1<string, string>(c1); // ~178ms
b = GetType2<string, string>(c1); // ~94ms
b = Is<string, string>(c1); // ~70ms
b = GetType1<string, Type>(c2); // ~178ms
b = GetType2<string, Type>(c2); // ~96ms
b = Is<string, Type>(c2); // ~65ms
b = GetType1<string, object>(oc1); // ~190ms
b = Is<string, object>(oc1); // ~69ms
b = GetType1<string, object>(oc2); // ~180ms
b = Is<string, object>(oc2); // ~64ms
b = GetType1<int, int>(s1); // ~230ms
b = GetType2<int, int>(s1); // ~75ms
b = Is<int, int>(s1); // ~136ms
b = GetType1<int, char>(s2); // ~238ms
b = GetType2<int, char>(s2); // ~69ms
b = Is<int, char>(s2); // ~142ms
b = GetType1<int, object>(os1); // ~178ms
b = Is<int, object>(os1); // ~69ms
b = GetType1<int, object>(os2); // ~178ms
b = Is<int, object>(os2); // ~69ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());
As funções genéricas para testar tipos genéricos:
static bool GetType1<S, T>(T t)
{
return t.GetType() == typeof(S);
}
static bool GetType2<S, T>(T t)
{
return typeof(T) == typeof(S);
}
static bool Is<S, T>(T t)
{
return t is S;
}
Tentei também tipos personalizados e os resultados foram consistentes:
var c1 = new Class1();
var c2 = new Class2();
object oc1 = c1;
object oc2 = c2;
var s1 = new Struct1();
var s2 = new Struct2();
object os1 = s1;
object os2 = s2;
bool b = false;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
b = c1.GetType() == typeof(Class1); // ~60ms
b = c1 is Class1; // ~60ms
b = c2.GetType() == typeof(Class1); // ~60ms
b = c2 is Class1; // ~55ms
b = oc1.GetType() == typeof(Class1); // ~60ms
b = oc1 is Class1; // ~68ms
b = oc2.GetType() == typeof(Class1); // ~60ms
b = oc2 is Class1; // ~68ms
b = s1.GetType() == typeof(Struct1); // ~150ms
b = s1 is Struct1; // ~50ms
b = s2.GetType() == typeof(Struct1); // ~150ms
b = s2 is Struct1; // ~50ms
b = os1.GetType() == typeof(Struct1); // ~60ms
b = os1 is Struct1; // ~64ms
b = os2.GetType() == typeof(Struct1); // ~60ms
b = os2 is Struct1; // ~64ms
b = GetType1<Class1, Class1>(c1); // ~178ms
b = GetType2<Class1, Class1>(c1); // ~98ms
b = Is<Class1, Class1>(c1); // ~78ms
b = GetType1<Class1, Class2>(c2); // ~178ms
b = GetType2<Class1, Class2>(c2); // ~96ms
b = Is<Class1, Class2>(c2); // ~69ms
b = GetType1<Class1, object>(oc1); // ~178ms
b = Is<Class1, object>(oc1); // ~69ms
b = GetType1<Class1, object>(oc2); // ~178ms
b = Is<Class1, object>(oc2); // ~69ms
b = GetType1<Struct1, Struct1>(s1); // ~272ms
b = GetType2<Struct1, Struct1>(s1); // ~140ms
b = Is<Struct1, Struct1>(s1); // ~163ms
b = GetType1<Struct1, Struct2>(s2); // ~272ms
b = GetType2<Struct1, Struct2>(s2); // ~140ms
b = Is<Struct1, Struct2>(s2); // ~163ms
b = GetType1<Struct1, object>(os1); // ~178ms
b = Is<Struct1, object>(os1); // ~64ms
b = GetType1<Struct1, object>(os2); // ~178ms
b = Is<Struct1, object>(os2); // ~64ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());
E os tipos:
sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }
Inferência:
Chamando GetType
em struct
s é mais lento. GetType
é definido na object
classe que não pode ser substituída em subtipos e, portanto, struct
precisa ser encaixotada para ser chamada GetType
.
Em uma instância de objeto, GetType
é mais rápido, mas muito marginalmente.
No tipo genérico, se T
for class
, então is
é muito mais rápido. Se T
for struct
, então is
é muito mais rápido que, GetType
mas typeof(T)
é muito mais rápido que ambos. Nos casos de T
ser class
, typeof(T)
não é confiável, pois é diferente do tipo subjacente real t.GetType
.
Em resumo, se você tiver uma object
instância, use GetType
. Se você tem um class
tipo genérico , use is
. Se você tem um struct
tipo genérico , use typeof(T)
. Se você não tiver certeza se o tipo genérico é o tipo de referência ou o valor, use is
. Se você quiser sempre ser consistente com um estilo (para tipos selados), use is
..