Risposte:
Questo dovrebbe rispondere a quella domanda, e poi alcuni.
La seconda linea, if (obj.GetType() == typeof(ClassA)) {}
è più veloce, per coloro che non vogliono leggere l'articolo.
(Ricorda che non fanno la stessa cosa)
typeof(string).TypeHandle
con l' ldtoken
istruzione CIL, ma sembra che CLR se ne occupi in JIT. Richiede ancora alcuni codici operativi aggiuntivi ma è un'applicazione più generalizzata dell'ottimizzazione.
GetType
, is
è sempre una scelta più sicura per quanto riguarda le prestazioni. Ovviamente fanno cose diverse.
object obj;
variabile, non è già inscatolata quando tende a essere testata? C'è un caso in cui è necessario testare il tipo di qualcosa e non è già inscatolato come oggetto?
Importa che è più veloce, se non fanno la stessa cosa? Confrontare le prestazioni delle dichiarazioni con significati diversi sembra una cattiva idea.
is
ti dice se l'oggetto si implementa ClassA
ovunque nel suo tipo di gerarchia. GetType()
ti parla del tipo più derivato.
Non è la stessa cosa
Non fanno la stessa cosa. Il primo funziona se obj è di tipo ClassA o di qualche sottoclasse di ClassA. Il secondo corrisponderà solo agli oggetti di tipo ClassA. Il secondo sarà più veloce poiché non deve controllare la gerarchia di classi.
Per coloro che vogliono conoscere il motivo, ma non vogliono leggere l'articolo a cui si fa riferimento è vs typeof .
Ho fatto alcuni benchmarking in cui fanno lo stesso - tipi sigillati.
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());
Le funzioni generiche per verificare i tipi generici:
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;
}
Ho provato anche per tipi personalizzati e i risultati sono stati coerenti:
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());
E i tipi:
sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }
Inferenza:
Chiamando GetType
il struct
s è più lento. GetType
è definito su una object
classe che non può essere sovrascritta nei sottotipi e quindi struct
deve essere inscatolata per essere chiamata GetType
.
Su un'istanza di oggetto, GetType
è più veloce, ma molto marginale.
Sul tipo generico, se lo T
è class
, allora is
è molto più veloce. Se lo T
è struct
, allora is
è molto più veloce di GetType
ma typeof(T)
è molto più veloce di entrambi. In casi di T
essere class
, typeof(T)
non è affidabile poiché è diverso dal tipo di base reale t.GetType
.
In breve, se si dispone di object
un'istanza, utilizzare GetType
. Se hai un class
tipo generico , usa is
. Se hai un struct
tipo generico , usa typeof(T)
. Se non si è sicuri che il tipo generico sia di tipo di riferimento o di valore, utilizzare is
. Se vuoi essere sempre coerente con uno stile (per i tipi sigillati), usa is
..