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)
typeof(string).TypeHandle
do ldtoken
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 implementuje ClassA
gdziekolwiek w swojej hierarchii typów. GetType()
informuje o typie najbardziej pochodnym.
To nie to samo.
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 .
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 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());
Funkcje ogólne do testowania dla typów ogólnych:
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;
}
Próbowałem również dla niestandardowych typów i wyniki były spójne:
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());
Oraz typy:
sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }
Wnioskowanie:
Dzwoniąc GetType
na struct
s wolniej. GetType
jest zdefiniowana w object
klasie, której nie można przesłonić w typach podrzędnych, a zatem struct
aby wywołać, należy ją spakować GetType
.
W instancji obiektu GetType
jest szybszy, ale bardzo marginalnie.
Na typie ogólnym, jeśli T
tak class
, is
jest znacznie szybsze. Jeśli T
tak struct
, to is
jest znacznie szybsze niż, GetType
ale typeof(T)
jest znacznie szybsze niż oba. W przypadku T
istoty 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 object
instancję, użyj GetType
. Jeśli masz class
typ ogólny , użyj is
. Jeśli masz struct
typ 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
...