是vs typeof


Answers:


167

这应该回答这个问题,然后再回答一些。

if (obj.GetType() == typeof(ClassA)) {}对于不想阅读本文的人,第二行更快。

(请注意,他们不会做相同的事情)


1
+1:过去我想知道为什么C#编译器没有编译typeof(string).TypeHandleldtokenCIL指令,但是看起来CLR在JIT中处理了它。它仍然需要一些额外的操作码,但这是优化的更一般化的应用。
山姆·哈威尔

2
也请阅读Higherlogics.blogspot.ca/2013/09/…-他们针对不同的框架以及x86与x64进行了重新测试,结果却大相径庭。
CAD bloke 2014年

1
请注意,这仅适用于引用类型。速度差异并不明显。鉴于装箱损失价值类型的情况下GetTypeis总是尽可能表现而言更安全的选择。当然,他们做不同的事情。
nawfal 2014年

如果您在Resharper中输入,建议将其更改为“ is”!
罗布·塞奇威克

@nawfal,我最初以为您对拳击罚分的观点对结构类型有意义,但鉴于我们正在测试object obj;变量,因此在测试变量时是否已经将其装箱了?是否存在需要测试某物类型并且尚未将其包装为对象的情况?
罗伯·帕克

193

如果他们不做同一件事,哪个更快更重要吗?比较具有不同含义的语句的性能似乎是个坏主意。

is告诉您对象是否ClassA在其类型层次结构中的任何地方实现。 GetType()告诉您最派生的类型。

不一样的东西。


7
这很重要,因为就我而言,我很肯定他们返回的结果相同。
ilitirit

37
@ [ilitirit]:它们现在会返回相同的结果,但是如果您以后添加子类,它们将不会
Steven A. Lowe

13
现在进行优化将使您的代码脆弱且难以维护。
ICR

9
我的课是密封的。
ilitirit

26

他们做的不一样。如果obj是ClassA类型或ClassA的某些子类,则第一个有效。第二个将仅匹配ClassA类型的对象。第二个将更快,因为它不必检查类层次结构。

对于那些想知道原因,但又不想阅读参考资料的人 是vs typeof


1
@amitjha我有点担心,因为该测试是在Mono下运行的,因此它不包括本文中引用的JIT优化。由于文章显示了相反的观点,因此在我看来,这个问题是一个开放的问题。无论如何,比较根据类型执行不同操作的操作的性能似乎是毫无价值的。使用与您需要的行为相匹配的操作,而不是“更快”的操作
tvanfosson

16

我做了一些基准测试,他们做了同样的事情-密封类型。

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());

测试泛型类型的泛型函数:

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;
}

我也尝试了自定义类型,结果是一致的:

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());

以及类型:

sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }

推理:

  1. 调用GetTypestructs是慢。 GetTypeobject类上定义的,不能在子类型中覆盖它,因此struct需要装箱以调用GetType

  2. 在对象实例上,GetType速度更快,但是非常有限。

  3. 在泛型上,如果Tclass,则is速度要快得多。如果Tstruct,则is比快得多,GetTypetypeof(T)比两者都快得多。在案件T之中classtypeof(T)是不是因为从实际的基本类型及其不同的可靠t.GetType

简而言之,如果您有object实例,请使用GetType。如果您具有通用class类型,请使用is。如果您具有通用struct类型,请使用typeof(T)。如果不确定泛型类型是引用类型还是值类型,请使用is。如果要始终与一种样式保持一致(对于密封类型),请使用is..


1
实际上,根本不在乎。使用最有意义的方法。
nawfal 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.