whats news new microsoft features docs compute c# rtti

c# - news - es vs typeof



new features c# (4)

¿Cuál de estos pedazos de código es más rápido?

if (obj is ClassA) {} if (obj.GetType() == typeof(ClassA)) {}

Editar: Soy consciente de que no hacen lo mismo.


¿Importa qué es más rápido si no hacen lo mismo? Comparar el rendimiento de las declaraciones con un significado diferente parece una mala idea.

te dice si el objeto implementa ClassA en cualquier lugar en su jerarquía de tipos. GetType() le informa sobre el tipo más derivado.

No es lo mismo.


Ellos no hacen lo mismo. El primero funciona si obj es de tipo ClassA o de alguna subclase de ClassA. El segundo solo coincidirá con objetos de tipo ClassA. El segundo será más rápido ya que no tiene que verificar la jerarquía de clases.

Para aquellos que quieran saber el motivo, pero no quieren leer el artículo al que se hace referencia en el presente .


Hice algunos benchmarking donde hacen lo mismo - tipos sellados.

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());

Las funciones genéricas para probar los 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; }

Intenté también para tipos personalizados y los resultados fueron 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());

Y los tipos:

sealed class Class1 { } sealed class Class2 { } struct Struct1 { } struct Struct2 { }

Inferencia:

  1. Llamar a GetType en struct s es más lento. GetType se define en la clase de object que no puede anularse en subtipos y, por lo tanto, las struct deben estar en recuadro para llamarse GetType .

  2. En una instancia de objeto, GetType es más rápido, pero muy marginal.

  3. En el tipo genérico, si T es class , entonces es mucho más rápido. Si T es struct , entonces is mucho más rápido que GetType pero typeof(T) es mucho más rápido que ambos. En los casos en que T es una class , typeof(T) no es confiable ya que es diferente del tipo subyacente real t.GetType .

En resumen, si tiene una instancia de object , use GetType . Si tiene un tipo de class genérico, use is . Si tiene un tipo de struct genérico, use typeof(T) . Si no está seguro de si el tipo genérico es el tipo de referencia o el tipo de valor, use is . Si quiere ser consistente con un estilo siempre (para tipos sellados), use is ...