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).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.
GetType, isjest 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.
isinformuje, czy obiekt implementuje ClassAgdziekolwiek 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 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...