Lequel de ces morceaux de code est plus rapide?
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
Edit: Je suis conscient qu'ils ne font pas la même chose.
Ceci devrait répondre à cette question, puis à quelques autres.
La deuxième ligne, if (obj.GetType() == typeof(ClassA)) {}
, est plus rapide pour ceux qui ne veulent pas lire l'article.
Est-ce qu'il importe de savoir ce qui est plus rapide, s'ils ne font pas la même chose? Comparer la performance d'énoncés de signification différente semble être une mauvaise idée.
is
vous indique si l'objet implémente ClassA
n'importe où dans son type hiérarchie. GetType()
vous indique le type le plus dérivé.
Pas la même chose.
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’aura pas à 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 is vs typeof .
J'ai fait une analyse comparative où ils font les mêmes 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 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());
Les fonctions génériques à tester pour les types génériques:
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;
}
J'ai également essayé des types personnalisés et les résultats étaient cohérents:
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());
Et les types:
sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }
Inférence:
L'appel de GetType
sur struct
s est plus lent.GetType
est défini sur object
La classe ne peut pas être remplacée par des sous-types et donc struct
s doivent être mis en boîte pour s'appeler GetType
.
Sur une instance d'objet, GetType
est plus rapide, mais très marginalement.
Sur le type générique, si T
est class
, alors is
est beaucoup plus rapide. Si T
est struct
, alors is
est beaucoup plus rapide que GetType
mais typeof(T)
est beaucoup plus rapide que les deux. Dans les cas où T
est class
, typeof(T)
n'est pas fiable car différent du type sous-jacent réel t.GetType
.
En bref, si vous avez une instance object
, utilisez GetType
. Si vous avez un type générique class
, utilisez is
. Si vous avez un type générique struct
, utilisez typeof(T)
. Si vous ne savez pas si le type générique est un type référence ou type valeur, utilisez is
. Si vous voulez toujours être cohérent avec un style (pour les types scellés), utilisez is
..