+1: En el pasado me preguntaba por qué el compilador de C # no compilaba typeof(string).TypeHandlela ldtokeninstrucción CIL, pero parece que el CLR se encarga de eso en el JIT. Todavía requiere algunos códigos de operación adicionales, pero es una aplicación más generalizada de la optimización.
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 de boxeo en caso de tipos de valor GetType, issiempre es una opción más segura en lo que respecta al rendimiento. Por supuesto que hacen cosas diferentes.
nawfal
¡Si pones eso en Resharper sugiere cambiarlo a "es"!
Rob Sedgwick el
@nawfal, inicialmente pensé que tu punto sobre la penalización del boxeo tenía sentido para los tipos de estructura, pero dado que estamos probando una object obj;variable, ¿no está ya encuadrada cuando esto tiende a probarse? ¿Hay algún caso en el que necesites probar el tipo de algo y aún no esté encuadrado como un objeto?
Rob Parker el
193
¿Importa cuál es más rápido si no hacen lo mismo? Comparar el desempeño de las declaraciones con diferentes significados parece una mala idea.
isle indica si el objeto se implementa ClassAen algún lugar de su jerarquía de tipos. GetType()le informa sobre el tipo más derivado.
Sí importa, porque en mi caso estoy seguro de que devuelven el mismo resultado.
ilitirit
37
@ [ilitirit]: ahora devuelven el mismo resultado, pero si agrega una subclase más tarde, no lo harán
Steven A. Lowe
13
La optimización ahora hará que su código sea frágil y difícil de mantener.
ICR
9
Mis clases están selladas.
ilitirit
26
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 la razón, pero no quieren leer el artículo al que se hace referencia en es vs typeof .
@amitjha Estoy un poco preocupado porque, debido a que esa prueba se ejecutó en Mono, no incluye las optimizaciones JIT mencionadas en el artículo. Como 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. Utilice la operación que coincida con el comportamiento que necesita, no el que es "más rápido"
tvanfosson
16
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 isstring;// ~60ms
b = c2.GetType()==typeof(string);// ~60ms
b = c2 isstring;// ~50ms
b = oc1.GetType()==typeof(string);// ~60ms
b = oc1 isstring;// ~68ms
b = oc2.GetType()==typeof(string);// ~60ms
b = oc2 isstring;// ~64ms
b = s1.GetType()==typeof(int);// ~130ms
b = s1 isint;// ~50ms
b = s2.GetType()==typeof(int);// ~140ms
b = s2 isint;// ~50ms
b = os1.GetType()==typeof(int);// ~60ms
b = os1 isint;// ~74ms
b = os2.GetType()==typeof(int);// ~60ms
b = os2 isint;// ~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:
staticboolGetType1<S, T>(T t){return t.GetType()==typeof(S);}staticboolGetType2<S, T>(T t){returntypeof(T)==typeof(S);}staticboolIs<S, T>(T t){return t is S;}
También probé los tipos personalizados y los resultados fueron consistentes:
var c1 =newClass1();var c2 =newClass2();object oc1 = c1;object oc2 = c2;var s1 =newStruct1();var s2 =newStruct2();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 isClass1;// ~60ms
b = c2.GetType()==typeof(Class1);// ~60ms
b = c2 isClass1;// ~55ms
b = oc1.GetType()==typeof(Class1);// ~60ms
b = oc1 isClass1;// ~68ms
b = oc2.GetType()==typeof(Class1);// ~60ms
b = oc2 isClass1;// ~68ms
b = s1.GetType()==typeof(Struct1);// ~150ms
b = s1 isStruct1;// ~50ms
b = s2.GetType()==typeof(Struct1);// ~150ms
b = s2 isStruct1;// ~50ms
b = os1.GetType()==typeof(Struct1);// ~60ms
b = os1 isStruct1;// ~64ms
b = os2.GetType()==typeof(Struct1);// ~60ms
b = os2 isStruct1;// ~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());
Llamar GetTypea structs es más lento. GetTypese define en una objectclase que no se puede anular en subtipos y, por lo tanto, se structdebe encuadrar para poder llamar GetType.
En una instancia de objeto, GetTypees más rápido, pero muy marginal.
En el tipo genérico, si Tes class, entonces ises mucho más rápido. Si Tes así struct, entonces ises mucho más rápido que, GetTypepero typeof(T)es mucho más rápido que ambos. En casos de Tser class, typeof(T)no es confiable ya que es diferente del tipo subyacente real t.GetType.
En resumen, si tiene una objectinstancia, use GetType. Si tiene un classtipo genérico , use is. Si tiene un structtipo genérico , use typeof(T). Si no está seguro si el tipo genérico es tipo de referencia o tipo de valor, use is. Si quiere ser consistente con un estilo siempre (para tipos sellados), use is...
Respuestas:
Esto debería responder esa pregunta, y algo más.
La segunda línea,
if (obj.GetType() == typeof(ClassA)) {}
es más rápida, para aquellos que no quieren leer el artículo.(Tenga en cuenta que no hacen lo mismo)
fuente
typeof(string).TypeHandle
laldtoken
instrucción CIL, pero parece que el CLR se encarga de eso en el JIT. Todavía requiere algunos códigos de operación adicionales, pero es una aplicación más generalizada de la optimización.GetType
,is
siempre es una opción más segura en lo que respecta al rendimiento. Por supuesto que hacen cosas diferentes.object obj;
variable, ¿no está ya encuadrada cuando esto tiende a probarse? ¿Hay algún caso en el que necesites probar el tipo de algo y aún no esté encuadrado como un objeto?¿Importa cuál es más rápido si no hacen lo mismo? Comparar el desempeño de las declaraciones con diferentes significados parece una mala idea.
is
le indica si el objeto se implementaClassA
en algún lugar de su jerarquía de tipos.GetType()
le informa sobre el tipo más derivado.No es lo mismo.
fuente
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 la razón, pero no quieren leer el artículo al que se hace referencia en es vs typeof .
fuente
Hice algunas evaluaciones comparativas donde hacen lo mismo: tipos sellados.
Las funciones genéricas para probar los tipos genéricos:
También probé los tipos personalizados y los resultados fueron consistentes:
Y los tipos:
Inferencia:
Llamar
GetType
astruct
s es más lento.GetType
se define en unaobject
clase que no se puede anular en subtipos y, por lo tanto, sestruct
debe encuadrar para poder llamarGetType
.En una instancia de objeto,
GetType
es más rápido, pero muy marginal.En el tipo genérico, si
T
esclass
, entoncesis
es mucho más rápido. SiT
es asístruct
, entoncesis
es mucho más rápido que,GetType
perotypeof(T)
es mucho más rápido que ambos. En casos deT
serclass
,typeof(T)
no es confiable ya que es diferente del tipo subyacente realt.GetType
.En resumen, si tiene una
object
instancia, useGetType
. Si tiene unclass
tipo genérico , useis
. Si tiene unstruct
tipo genérico , usetypeof(T)
. Si no está seguro si el tipo genérico es tipo de referencia o tipo de valor, useis
. Si quiere ser consistente con un estilo siempre (para tipos sellados), useis
...fuente