+1: Dans le passé, je me demandais pourquoi le compilateur C # ne se compilait pas typeof(string).TypeHandleavec l' ldtokeninstruction CIL, mais il semble que le CLR s'en occupe dans le JIT. Il faut encore quelques opcodes supplémentaires mais c'est une application plus généralisée de l'optimisation.
Sam Harwell
2
Lisez aussi Higherlogics.blogspot.ca/2013/09/… - ils retestent pour différents frameworks et x86 vs x64 avec des résultats très différents.
Bloke CAD
1
Veuillez noter que cela n'est vrai que pour les types de référence. Et la différence de vitesse n'est pas si significative. Compte tenu de la pénalité de boxe en cas de types de valeur pour GetType, isest toujours un choix plus sûr en ce qui concerne les performances. Bien sûr, ils font des choses différentes.
nawfal
Si vous mettez cela dans Resharper suggère de le changer en "est"!
Rob Sedgwick
@nawfal, j'ai d'abord pensé que votre remarque sur la pénalité de boxe avait du sens pour les types de struct, mais étant donné que nous testons une object obj;variable, n'est-elle pas déjà encadrée lorsque cela a tendance à être testé? Y a-t-il un cas où vous devez tester le type de quelque chose et qu'il n'est pas déjà encadré en tant qu'objet?
Rob Parker
193
Est-ce que ce qui est le plus rapide importe, s'ils ne font pas la même chose? Comparer les performances d'énoncés ayant une signification différente semble être une mauvaise idée.
isvous indique si l'objet implémente ClassAn'importe où dans son héritage de type. GetType()vous indique le type le plus dérivé.
C'est important, car dans mon cas, je suis sûr qu'ils renvoient le même résultat.
ilitirit
37
@ [ilitirit]: ils renvoient le même résultat pour le moment, mais si vous ajoutez une sous-classe plus tard, ils ne le feront pas
Steven A. Lowe
13
L'optimisation maintenant rendra votre code fragile et difficile à maintenir.
ICR
9
Mes cours sont scellés.
ilitirit
26
Ils ne font pas la même chose. Le premier fonctionne si obj est de type ClassA ou d'une sous-classe de ClassA. Le second ne correspondra qu'aux objets de type ClassA. Le second sera plus rapide car il n'a pas besoin de vérifier la hiérarchie des classes.
Pour ceux qui veulent connaître la raison, mais ne veulent pas lire l'article référencé dans est vs typeof .
@amitjha Je suis un peu inquiet parce que ce test a été exécuté sous Mono qu'il n'inclut pas les optimisations JIT référencées dans l'article. Puisque l'article montre le contraire, dans mon esprit, la question est ouverte. Dans tous les cas, comparer les performances d'opérations qui font des choses différentes selon le type semble un exercice inutile. Utilisez l'opération qui correspond au comportement dont vous avez besoin, pas celle qui est "plus rapide"
tvanfosson
16
J'ai fait des analyses comparatives là où ils font la même chose - des types scellés.
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());
Les fonctions génériques à tester pour les types génériques:
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;}
J'ai également essayé des types personnalisés et les résultats étaient cohérents:
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());
L'appel GetTypesur structs est plus lent. GetTypeest défini sur une objectclasse qui ne peut pas être remplacée dans les sous-types et donc les structs doivent être encadrés pour être appelés GetType.
Sur une instance d'objet, GetTypec'est plus rapide, mais très marginalement.
Sur le type générique, si Tc'est le cas class, alors isc'est beaucoup plus rapide. Si Tc'est le cas struct, alors isc'est beaucoup plus rapide que GetTypemais typeof(T)c'est beaucoup plus rapide que les deux. En cas d' Têtre class, typeof(T)n'est pas fiable car il est différent du type sous-jacent réel t.GetType.
En bref, si vous avez une objectinstance, utilisez GetType. Si vous avez un classtype générique , utilisez is. Si vous avez un structtype générique , utilisez typeof(T). Si vous ne savez pas si le type générique est un type référence ou un type valeur, utilisez is. Si vous voulez toujours être cohérent avec un style (pour les types scellés), utilisez is..
Réponses:
Cela devrait répondre à cette question, et plus encore.
La deuxième ligne,
if (obj.GetType() == typeof(ClassA)) {}
est plus rapide, pour ceux qui ne veulent pas lire l'article.(Sachez qu'ils ne font pas la même chose)
la source
typeof(string).TypeHandle
avec l'ldtoken
instruction CIL, mais il semble que le CLR s'en occupe dans le JIT. Il faut encore quelques opcodes supplémentaires mais c'est une application plus généralisée de l'optimisation.GetType
,is
est toujours un choix plus sûr en ce qui concerne les performances. Bien sûr, ils font des choses différentes.object obj;
variable, n'est-elle pas déjà encadrée lorsque cela a tendance à être testé? Y a-t-il un cas où vous devez tester le type de quelque chose et qu'il n'est pas déjà encadré en tant qu'objet?Est-ce que ce qui est le plus rapide importe, s'ils ne font pas la même chose? Comparer les performances d'énoncés ayant une signification différente semble être une mauvaise idée.
is
vous indique si l'objet implémenteClassA
n'importe où dans son héritage de type.GetType()
vous indique le type le plus dérivé.Pas la même chose.
la source
Ils ne font pas la même chose. Le premier fonctionne si obj est de type ClassA ou d'une sous-classe de ClassA. Le second ne correspondra qu'aux objets de type ClassA. Le second sera plus rapide car il n'a pas besoin de vérifier la hiérarchie des classes.
Pour ceux qui veulent connaître la raison, mais ne veulent pas lire l'article référencé dans est vs typeof .
la source
J'ai fait des analyses comparatives là où ils font la même chose - des types scellés.
Les fonctions génériques à tester pour les types génériques:
J'ai également essayé des types personnalisés et les résultats étaient cohérents:
Et les types:
Inférence:
L'appel
GetType
surstruct
s est plus lent.GetType
est défini sur uneobject
classe qui ne peut pas être remplacée dans les sous-types et donc lesstruct
s doivent être encadrés pour être appelésGetType
.Sur une instance d'objet,
GetType
c'est plus rapide, mais très marginalement.Sur le type générique, si
T
c'est le casclass
, alorsis
c'est beaucoup plus rapide. SiT
c'est le casstruct
, alorsis
c'est beaucoup plus rapide queGetType
maistypeof(T)
c'est beaucoup plus rapide que les deux. En cas d'T
êtreclass
,typeof(T)
n'est pas fiable car il est différent du type sous-jacent réelt.GetType
.En bref, si vous avez une
object
instance, utilisezGetType
. Si vous avez unclass
type générique , utilisezis
. Si vous avez unstruct
type générique , utiliseztypeof(T)
. Si vous ne savez pas si le type générique est un type référence ou un type valeur, utilisezis
. Si vous voulez toujours être cohérent avec un style (pour les types scellés), utilisezis
..la source