+1: In der Vergangenheit habe ich mich gefragt, warum der C # -Compiler nicht typeof(string).TypeHandlemit der ldtokenCIL-Anweisung kompiliert wurde , aber es sieht so aus, als würde sich die CLR in der JIT darum kümmern. Es werden noch einige zusätzliche Opcodes benötigt, aber es handelt sich um eine allgemeinere Anwendung der Optimierung.
Bitte beachten Sie, dass dies nur für Referenztypen gilt. Und der Geschwindigkeitsunterschied ist nicht so signifikant. Angesichts der Box - Strafe bei Werttypen für GetType, isist immer eine sicherere Wahl so weit wie Leistung angeht. Natürlich machen sie verschiedene Dinge.
Nawfal
Wenn Sie dies in Resharper eingeben, wird vorgeschlagen, es in "ist" zu ändern!
Rob Sedgwick
@nawfal, ich dachte anfangs, dass Ihr Standpunkt zur Boxstrafe für Strukturtypen sinnvoll ist, aber angesichts der Tatsache, dass wir eine object obj;Variable testen , ist sie nicht bereits boxen, wenn dies tendenziell getestet wird? Gibt es einen Fall, in dem Sie den Typ von etwas testen müssen und es nicht bereits als Objekt verpackt ist?
Rob Parker
193
Ist es wichtig, was schneller ist, wenn sie nicht dasselbe tun? Der Vergleich der Leistung von Aussagen mit unterschiedlicher Bedeutung scheint eine schlechte Idee zu sein.
isteilt Ihnen mit, ob das Objekt ClassAirgendwo in seiner Typ-Hierarchie implementiert ist. GetType()informiert Sie über den am meisten abgeleiteten Typ.
Es ist wichtig, denn in meinem Fall bin ich mir sicher, dass sie das gleiche Ergebnis liefern.
ilitirit
37
@ [ilitirit]: Sie geben das gleiche Ergebnis im Moment zurück, aber wenn Sie später eine Unterklasse hinzufügen, werden sie nicht
Steven A. Lowe
13
Wenn Sie jetzt optimieren, wird Ihr Code spröde und schwer zu pflegen.
ICR
9
Meine Klassen sind versiegelt.
ilitirit
26
Sie machen nicht das Gleiche. Das erste funktioniert, wenn obj vom Typ ClassA oder einer Unterklasse von ClassA ist. Der zweite entspricht nur Objekten vom Typ ClassA. Der zweite ist schneller, da die Klassenhierarchie nicht überprüft werden muss.
Für diejenigen, die den Grund wissen möchten, aber den Artikel, auf den verwiesen wird, nicht lesen möchten ist vs typeof .
@amitjha Ich bin ein wenig besorgt darüber, dass dieser Test, der unter Mono ausgeführt wurde, die im Artikel genannten JIT-Optimierungen nicht enthält. Da der Artikel das Gegenteil zeigt, ist die Frage meiner Meinung nach offen. In jedem Fall scheint es eine wertlose Übung zu sein, die Leistung von Operationen zu vergleichen, die je nach Typ unterschiedliche Aufgaben ausführen. Verwenden Sie die Operation, die dem von Ihnen benötigten Verhalten entspricht, nicht die, die "schneller" ist
tvanfosson
16
Ich habe ein Benchmarking durchgeführt, bei dem die gleichen versiegelten Typen verwendet werden.
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());
Die generischen Funktionen zum Testen auf generische Typen:
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;}
Ich habe auch nach benutzerdefinierten Typen gesucht und die Ergebnisse waren konsistent:
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());
Das Aufrufen GetTypevon structs ist langsamer. GetTypewird für eine objectKlasse definiert , die in Untertypen nicht überschrieben werden kann und daher structzum Aufrufen eingerahmt werden muss GetType.
Auf einer Objektinstanz GetTypeist schneller, aber sehr marginal.
Wenn dies beim generischen Typ der Fall Tist class, isist dies viel schneller. Wenn Tja struct, dann isist es viel schneller als, GetTypeaber typeof(T)viel schneller als beide. In Fällen von TWesen class, typeof(T)ist seit seiner verschiedenen nicht zuverlässig von den tatsächlichen zugrunde liegenden Typ t.GetType.
Kurz gesagt, wenn Sie eine objectInstanz haben, verwenden Sie GetType. Wenn Sie einen generischen classTyp haben, verwenden Sie is. Wenn Sie einen generischen structTyp haben, verwenden Sie typeof(T). Wenn Sie sich nicht sicher sind, ob der generische Typ der Referenztyp oder der Werttyp ist, verwenden Sie is. Wenn Sie immer mit einem Stil übereinstimmen möchten (für versiegelte Typen), verwenden Sie is..
Antworten:
Dies sollte diese und noch einige weitere Fragen beantworten.
Die zweite Zeile
if (obj.GetType() == typeof(ClassA)) {}
ist schneller für diejenigen, die den Artikel nicht lesen möchten.(Seien Sie sich bewusst, dass sie nicht dasselbe tun)
quelle
typeof(string).TypeHandle
mit derldtoken
CIL-Anweisung kompiliert wurde , aber es sieht so aus, als würde sich die CLR in der JIT darum kümmern. Es werden noch einige zusätzliche Opcodes benötigt, aber es handelt sich um eine allgemeinere Anwendung der Optimierung.GetType
,is
ist immer eine sicherere Wahl so weit wie Leistung angeht. Natürlich machen sie verschiedene Dinge.object obj;
Variable testen , ist sie nicht bereits boxen, wenn dies tendenziell getestet wird? Gibt es einen Fall, in dem Sie den Typ von etwas testen müssen und es nicht bereits als Objekt verpackt ist?Ist es wichtig, was schneller ist, wenn sie nicht dasselbe tun? Der Vergleich der Leistung von Aussagen mit unterschiedlicher Bedeutung scheint eine schlechte Idee zu sein.
is
teilt Ihnen mit, ob das ObjektClassA
irgendwo in seiner Typ-Hierarchie implementiert ist.GetType()
informiert Sie über den am meisten abgeleiteten Typ.Nicht dasselbe.
quelle
Sie machen nicht das Gleiche. Das erste funktioniert, wenn obj vom Typ ClassA oder einer Unterklasse von ClassA ist. Der zweite entspricht nur Objekten vom Typ ClassA. Der zweite ist schneller, da die Klassenhierarchie nicht überprüft werden muss.
Für diejenigen, die den Grund wissen möchten, aber den Artikel, auf den verwiesen wird, nicht lesen möchten ist vs typeof .
quelle
Ich habe ein Benchmarking durchgeführt, bei dem die gleichen versiegelten Typen verwendet werden.
Die generischen Funktionen zum Testen auf generische Typen:
Ich habe auch nach benutzerdefinierten Typen gesucht und die Ergebnisse waren konsistent:
Und die Typen:
Inferenz:
Das Aufrufen
GetType
vonstruct
s ist langsamer.GetType
wird für eineobject
Klasse definiert , die in Untertypen nicht überschrieben werden kann und daherstruct
zum Aufrufen eingerahmt werden mussGetType
.Auf einer Objektinstanz
GetType
ist schneller, aber sehr marginal.Wenn dies beim generischen Typ der Fall
T
istclass
,is
ist dies viel schneller. WennT
jastruct
, dannis
ist es viel schneller als,GetType
abertypeof(T)
viel schneller als beide. In Fällen vonT
Wesenclass
,typeof(T)
ist seit seiner verschiedenen nicht zuverlässig von den tatsächlichen zugrunde liegenden Typt.GetType
.Kurz gesagt, wenn Sie eine
object
Instanz haben, verwenden SieGetType
. Wenn Sie einen generischenclass
Typ haben, verwenden Sieis
. Wenn Sie einen generischenstruct
Typ haben, verwenden Sietypeof(T)
. Wenn Sie sich nicht sicher sind, ob der generische Typ der Referenztyp oder der Werttyp ist, verwenden Sieis
. Wenn Sie immer mit einem Stil übereinstimmen möchten (für versiegelte Typen), verwenden Sieis
..quelle