+1: W przeszłości zastanawiałem się, dlaczego kompilator C # nie skompilował się typeof(string).TypeHandledo ldtokeninstrukcji CIL, ale wygląda na to, że CLR zajmuje się tym w JIT. Nadal wymaga kilku dodatkowych instrukcji, ale jest to bardziej uogólniona aplikacja optymalizacji.
Należy pamiętać, że dotyczy to tylko typów referencyjnych. A różnica prędkości nie jest tak znacząca. Biorąc pod uwagę karę bokserską w przypadku typów wartości GetType, isjest to zawsze bezpieczniejszy wybór, jeśli chodzi o wydajność. Oczywiście robią różne rzeczy.
nawfal
Jeśli umieścisz to w Resharper sugeruje zmianę na „jest”!
Rob Sedgwick
@nawfal, początkowo myślałem, że twój punkt widzenia dotyczący kary bokserskiej ma sens w przypadku typów struktur, ale biorąc pod uwagę, że testujemy object obj;zmienną, czy nie jest już opakowana, gdy ma być testowana? Czy jest przypadek, w którym musisz przetestować typ czegoś i nie jest to już opakowane jako obiekt?
Rob Parker
193
Czy ma znaczenie, który jest szybszy, jeśli nie robią tego samego? Porównanie wykonania wypowiedzi o różnym znaczeniu wydaje się złym pomysłem.
isinformuje, czy obiekt implementuje ClassAgdziekolwiek w swojej hierarchii typów. GetType()informuje o typie najbardziej pochodnym.
Ma to znaczenie, ponieważ w moim przypadku jestem pewien, że zwracają ten sam wynik.
ilitirit
37
@ [ilitirit]: teraz zwracają ten sam wynik, ale jeśli później dodasz podklasę, nie
Steven A. Lowe
13
Optymalizacja teraz sprawi, że Twój kod będzie kruchy i trudny w utrzymaniu.
ICR
9
Moje zajęcia są zapieczętowane.
ilitirit
26
Nie robią tego samego. Pierwsza działa, jeśli obj jest typu ClassA lub jakiejś podklasy ClassA. Drugi będzie pasował tylko do obiektów typu ClassA. Drugi będzie szybszy, ponieważ nie musi sprawdzać hierarchii klas.
Dla tych, którzy chcą poznać przyczynę, ale nie chcą czytać artykułu, do którego się odwołuje jest vs typeof .
@amitjha Jestem trochę zaniepokojony tym, że ponieważ ten test został uruchomiony w Mono, nie zawiera on optymalizacji JIT, o których mowa w artykule. Ponieważ artykuł pokazuje coś przeciwnego, moim zdaniem pytanie jest otwarte. W każdym razie porównywanie wykonywania operacji, które robią różne rzeczy w zależności od rodzaju, wydaje się bezwartościowym ćwiczeniem. Użyj operacji, która odpowiada wymaganemu zachowaniu, a nie tej, która jest „szybsza”
tvanfosson
16
Zrobiłem kilka testów porównawczych, gdzie robią to samo - zapieczętowane typy.
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());
Funkcje ogólne do testowania dla typów ogólnych:
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;}
Próbowałem również dla niestandardowych typów i wyniki były spójne:
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());
Dzwoniąc GetTypena structs wolniej. GetTypejest zdefiniowana w objectklasie, której nie można przesłonić w typach podrzędnych, a zatem structaby wywołać, należy ją spakować GetType.
W instancji obiektu GetTypejest szybszy, ale bardzo marginalnie.
Na typie ogólnym, jeśli Ttak class, isjest znacznie szybsze. Jeśli Ttak struct, to isjest znacznie szybsze niż, GetTypeale typeof(T)jest znacznie szybsze niż oba. W przypadku Tistoty class, typeof(T)nie jest wiarygodne, ponieważ jego różni się od rzeczywistego typu bazowego t.GetType.
Krótko mówiąc, jeśli masz objectinstancję, użyj GetType. Jeśli masz classtyp ogólny , użyj is. Jeśli masz structtyp ogólny , użyj typeof(T). Jeśli nie masz pewności, czy typ ogólny jest typem referencyjnym, czy typem wartości, użyj is. Jeśli chcesz zawsze zachować spójność z jednym stylem (dla typów zapieczętowanych), użyj is...
Odpowiedzi:
To powinno odpowiedzieć na to pytanie, a potem na niektóre.
Drugi wiersz
if (obj.GetType() == typeof(ClassA)) {}
jest szybszy dla tych, którzy nie chcą czytać artykułu.(Pamiętaj, że nie robią tego samego)
źródło
typeof(string).TypeHandle
doldtoken
instrukcji CIL, ale wygląda na to, że CLR zajmuje się tym w JIT. Nadal wymaga kilku dodatkowych instrukcji, ale jest to bardziej uogólniona aplikacja optymalizacji.GetType
,is
jest to zawsze bezpieczniejszy wybór, jeśli chodzi o wydajność. Oczywiście robią różne rzeczy.object obj;
zmienną, czy nie jest już opakowana, gdy ma być testowana? Czy jest przypadek, w którym musisz przetestować typ czegoś i nie jest to już opakowane jako obiekt?Czy ma znaczenie, który jest szybszy, jeśli nie robią tego samego? Porównanie wykonania wypowiedzi o różnym znaczeniu wydaje się złym pomysłem.
is
informuje, czy obiekt implementujeClassA
gdziekolwiek w swojej hierarchii typów.GetType()
informuje o typie najbardziej pochodnym.To nie to samo.
źródło
Nie robią tego samego. Pierwsza działa, jeśli obj jest typu ClassA lub jakiejś podklasy ClassA. Drugi będzie pasował tylko do obiektów typu ClassA. Drugi będzie szybszy, ponieważ nie musi sprawdzać hierarchii klas.
Dla tych, którzy chcą poznać przyczynę, ale nie chcą czytać artykułu, do którego się odwołuje jest vs typeof .
źródło
Zrobiłem kilka testów porównawczych, gdzie robią to samo - zapieczętowane typy.
Funkcje ogólne do testowania dla typów ogólnych:
Próbowałem również dla niestandardowych typów i wyniki były spójne:
Oraz typy:
Wnioskowanie:
Dzwoniąc
GetType
nastruct
s wolniej.GetType
jest zdefiniowana wobject
klasie, której nie można przesłonić w typach podrzędnych, a zatemstruct
aby wywołać, należy ją spakowaćGetType
.W instancji obiektu
GetType
jest szybszy, ale bardzo marginalnie.Na typie ogólnym, jeśli
T
takclass
,is
jest znacznie szybsze. JeśliT
takstruct
, tois
jest znacznie szybsze niż,GetType
aletypeof(T)
jest znacznie szybsze niż oba. W przypadkuT
istotyclass
,typeof(T)
nie jest wiarygodne, ponieważ jego różni się od rzeczywistego typu bazowegot.GetType
.Krótko mówiąc, jeśli masz
object
instancję, użyjGetType
. Jeśli maszclass
typ ogólny , użyjis
. Jeśli maszstruct
typ ogólny , użyjtypeof(T)
. Jeśli nie masz pewności, czy typ ogólny jest typem referencyjnym, czy typem wartości, użyjis
. Jeśli chcesz zawsze zachować spójność z jednym stylem (dla typów zapieczętowanych), użyjis
...źródło