¿Cuál de estos fragmentos de código es más rápido?es vs typeof
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
Editar: Soy consciente de que no hacen lo mismo.
¿Cuál de estos fragmentos de código es más rápido?es vs typeof
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
Editar: Soy consciente de que no hacen lo mismo.
This should answer that question, and then some.
La segunda línea, if (obj.GetType() == typeof(ClassA)) {}
, es más rápido, para aquellos que no quieren leer el artículo.
+1: En el pasado me preguntaba por qué el compilador C# no compilaba 'typeof (string) .TypeHandle' con la instrucción CIL' ldtoken', pero parece que CLR se encarga de ello en el JIT. Todavía requiere algunos códigos de operación adicionales, pero es una aplicación más general de la optimización. –
Lea http://higherlogics.blogspot.ca/2013/09/clr-cost-of-dynamic-type-tests.html también: vuelven a realizar pruebas para diferentes marcos y x86 frente a x64 con resultados muy diferentes. –
Tenga en cuenta que esto es cierto solo para los tipos de referencia. Y la diferencia de velocidad no es tan significativa. Dada la penalización del boxeo en el caso de los tipos de valor para 'GetType',' is' es siempre una opción más segura en lo que respecta al rendimiento. Por supuesto que hacen cosas diferentes. – nawfal
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 quieren saber el motivo, pero no quieren leer el artículo al que se hace referencia en is vs typeof.
http://stackoverflow.com/q/27813304 dice 'Objeto es tipo' será más rápido. –
@amitjha Estoy un poco preocupado porque esa prueba se ejecutó bajo Mono que no incluye las optimizaciones JIT a las que se hace referencia en el artículo. Dado que el artículo muestra lo contrario, en mi opinión, la pregunta es abierta. En cualquier caso, comparar el rendimiento de las operaciones que hacen cosas diferentes según el tipo parece un ejercicio inútil. Use la operación que coincida con el comportamiento que necesita, no el que es "más rápido" – tvanfosson
¿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.
is
indica si el objeto implementa ClassA
en cualquier lugar de su tipo jerarquía. GetType()
le informa sobre el tipo más derivado.
No es lo mismo.
Hice algunas evaluaciones comparativas 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 de prueba para 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;
}
Me trataron de tipos personalizados también 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:
GetType
Llamada en struct
s es más lento.GetType
se define en la clase object
que no se puede anular en subtipos y, por lo tanto, struct
s deben estar en el recuadro para llamarse GetType
.
En una instancia de objeto, GetType
es más rápido, pero muy marginal.
El tipo genérico, si es T
class
, entonces is
es mucho más rápido. Si T
es struct
, entonces is
es 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 class
, typeof(T)
no es confiable ya que es diferente del tipo subyacente real t.GetType
.
En pocas palabras, si usted tiene una instancia object
, utilice GetType
. Si tiene un tipo genérico class
, use is
. Si tiene un tipo genérico struct
, use typeof(T)
. Si no está seguro de si el tipo genérico es tipo de referencia o valor, use is
. Si quiere ser coherente con un estilo siempre (para tipos sellados), use is
..
En realidad, no te importa en absoluto. Usa lo que tenga más sentido. – nawfal
Respondió una pregunta similar aquí: http://stackoverflow.com/questions/57701/what-are-the-performance-characteristics -of-is-reflection-in-C# 57713 – swilliams