é vs typeof


Respostas:


167

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)


1
+1: No passado, eu me perguntava por que o compilador C # não foi compilado typeof(string).TypeHandlecom a ldtokeninstruçã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.
Sam Harwell

2
Leia upperlogics.blogspot.ca/2013/09/… também - eles testam novamente para diferentes estruturas e x86 x x64 com resultados amplamente diferentes.
CAD cara

1
Observe que isso é verdade apenas para tipos de referência. E a diferença de velocidade não é tão significativa. Dada a penalidade de boxe em caso de tipos de valor GetType, isé sempre uma escolha mais segura no que diz respeito ao desempenho. Claro que eles fazem coisas diferentes.
Nawfal 4/08

Se você colocar isso no Resharper, sugira alterá-lo para "é"!
Rob Sedgwick

@awawfal, inicialmente pensei que seu ponto sobre a penalidade de boxe fazia sentido para os tipos de estruturas, mas, como estamos testando uma 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?
22420 Robbie Parker

193

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.

isinforma se o objeto implementa ClassAem qualquer lugar da hierarquia de tipos. GetType()informa sobre o tipo mais derivado.

Não é a mesma coisa.


7
Importa, porque no meu caso, tenho certeza de que eles retornam o mesmo resultado.
Ilitirit 8/10/08

37
@ [ilitirit]: eles retornam o mesmo resultado agora, mas se você adicionar uma subclasse mais tarde, eles não serão
Steven A. Lowe

13
A otimização agora tornará seu código frágil e difícil de manter.
ICR

9
Minhas aulas são seladas.
Ilitirit 10/10/08

26

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 .


1
@amitjha Estou um pouco preocupado que, porque esse teste foi executado no Mono, ele não inclui as otimizações de JIT mencionadas no artigo. Como o artigo mostra o contrário, na minha opinião a questão é aberta. De qualquer forma, comparar o desempenho de operações que fazem coisas diferentes, dependendo do tipo, parece um exercício inútil. Use a operação que corresponde ao comportamento que você precisa, não o que é "mais rápido"
tvanfosson

16

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:

  1. Chamando GetTypeem structs é mais lento. GetTypeé definido na objectclasse que não pode ser substituída em subtipos e, portanto, structprecisa ser encaixotada para ser chamada GetType.

  2. Em uma instância de objeto, GetTypeé mais rápido, mas muito marginalmente.

  3. No tipo genérico, se Tfor class, então isé muito mais rápido. Se Tfor struct, então isé muito mais rápido que, GetTypemas typeof(T)é muito mais rápido que ambos. Nos casos de Tser class, typeof(T)não é confiável, pois é diferente do tipo subjacente real t.GetType.

Em resumo, se você tiver uma objectinstância, use GetType. Se você tem um classtipo genérico , use is. Se você tem um structtipo 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..


1
Na realidade, não me importo. Use o que faz mais sentido.
Nawfal
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.