Which of these pieces of code is faster?
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
Edit: I'm aware that they don't do the same thing.
Which of these pieces of code is faster?
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
Edit: I'm aware that they don't do the same thing.
This should answer that question, and then some.
The second line, if (obj.GetType() == typeof(ClassA)) {}
, is faster, for those that don't want to read the article.
(Be aware that they don't do the same thing)
typeof(string).TypeHandle
to the ldtoken
CIL instruction, but it looks like the CLR takes care of it in the JIT. It still takes a few extra opcodes but it's a more generalized application of the optimization. –
Doting GetType
, is
is always a safer choice as far as performance is concerned. Of course they do different things. –
Lugubrious object obj;
variable, isn't it already boxed when this tends to be tested? Is there a case where you need to test the type of something and it isn't already boxed as an object? –
Counterpoint GetType() == typeof
approach was the fastest (least wasteful) and FxCop warned not to use is
(as
is better, but not possible for struct types; FxCop may not have warned for is
with a struct type). Perhaps is
is more optimized in .NET 4.x than it used to be in .NET 2.0? –
Counterpoint object
variable, then you are right, calling GetType
makes no difference. But I am not sure if that is the case in the given link. –
Lugubrious IInterfaceForMyStruct myStruct = new MyStruct();
leads to a boxed variable. Of course all structs and enums inherit from a common base class ValueType
(which in turn inherit from object
leading to unified type system) but user defined value types cant inherit anything, only implement. –
Lugubrious mystruct is MyStruct
rather than mystruct.GetType()
which will cause boxing. Perhaps useful in generic contexts. –
Lugubrious Does it matter which is faster, if they don't do the same thing? Comparing the performance of statements with different meaning seems like a bad idea.
is
tells you if the object implements ClassA
anywhere in its type heirarchy. GetType()
tells you about the most-derived type.
Not the same thing.
This should answer that question, and then some.
The second line, if (obj.GetType() == typeof(ClassA)) {}
, is faster, for those that don't want to read the article.
(Be aware that they don't do the same thing)
typeof(string).TypeHandle
to the ldtoken
CIL instruction, but it looks like the CLR takes care of it in the JIT. It still takes a few extra opcodes but it's a more generalized application of the optimization. –
Doting GetType
, is
is always a safer choice as far as performance is concerned. Of course they do different things. –
Lugubrious object obj;
variable, isn't it already boxed when this tends to be tested? Is there a case where you need to test the type of something and it isn't already boxed as an object? –
Counterpoint GetType() == typeof
approach was the fastest (least wasteful) and FxCop warned not to use is
(as
is better, but not possible for struct types; FxCop may not have warned for is
with a struct type). Perhaps is
is more optimized in .NET 4.x than it used to be in .NET 2.0? –
Counterpoint object
variable, then you are right, calling GetType
makes no difference. But I am not sure if that is the case in the given link. –
Lugubrious IInterfaceForMyStruct myStruct = new MyStruct();
leads to a boxed variable. Of course all structs and enums inherit from a common base class ValueType
(which in turn inherit from object
leading to unified type system) but user defined value types cant inherit anything, only implement. –
Lugubrious mystruct is MyStruct
rather than mystruct.GetType()
which will cause boxing. Perhaps useful in generic contexts. –
Lugubrious They don't do the same thing. The first one works if obj is of type ClassA or of some subclass of ClassA. The second one will only match objects of type ClassA. The second one will be faster since it doesn't have to check the class hierarchy.
For those who want to know the reason, but don't want to read the article referenced in is vs typeof.
I did some benchmarking where they do the same - sealed types.
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());
The generic functions to test for generic types:
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;
}
I tried for custom types as well and the results were consistent:
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());
And the types:
sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }
Inference:
Calling GetType
on struct
s is slower. GetType
is defined on object
class which can't be overridden in sub types and thus struct
s need to be boxed to be called GetType
.
On an object instance, GetType
is faster, but very marginally.
On generic type, if T
is class
, then is
is much faster. If T
is struct
, then is
is much faster than GetType
but typeof(T)
is much faster than both. In cases of T
being class
, typeof(T)
is not reliable since its different from actual underlying type t.GetType
.
In short, if you have an object
instance, use GetType
. If you have a generic class
type, use is
. If you have a generic struct
type, use typeof(T)
. If you are unsure if generic type is reference type or value type, use is
. If you want to be consistent with one style always (for sealed types), use is
..
© 2022 - 2024 — McMap. All rights reserved.