is vs typeof

Posted

技术标签:

【中文标题】is vs typeof【英文标题】: 【发布时间】:2010-09-16 03:04:41 【问题描述】:

这些代码中哪一个更快?

if (obj is ClassA) 

if (obj.GetType() == typeof(ClassA)) 

编辑: 我知道他们不会做同样的事情。

【问题讨论】:

在这里回答了类似的问题:***.com/questions/57701/… 【参考方案1】:

This should answer that question, and then some.

第二行,if (obj.GetType() == typeof(ClassA)) ,对于那些不想阅读文章的人来说更快。

(注意他们不会做同样的事情)

【讨论】:

+1:过去我想知道为什么 C# 编译器没有将 typeof(string).TypeHandle 编译为 ldtoken CIL 指令,但看起来 CLR 在 JIT 中处理了它。它仍然需要一些额外的操作码,但它是一种更通用的优化应用。 也阅读higherlogics.blogspot.ca/2013/09/… - 他们针对不同的框架和 x86 与 x64 重新测试,结果大相径庭。 请注意,这仅适用于引用类型。而且速度差异不是那么显着。考虑到 GetType 的值类型的装箱惩罚,就性能而言,is 始终是更安全的选择。他们当然做不同的事情。 如果你把它放在 Resharper 建议把它改成 "is"! @nawfal,我最初认为你关于装箱惩罚的观点对于结构类型是有意义的,但鉴于我们正在测试一个 object obj; 变量,当这往往是时它不是已经装箱了吗?测试?是否存在您需要测试某物的类型但尚未将其装箱为对象的情况?【参考方案2】:

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

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  

推理:

    structs 上调用GetType 更慢。 GetType 是在object 类上定义的,它不能在子类型中被覆盖,因此structs需要装箱才能称为GetType

    在对象实例上,GetType 更快,但非常有限。

    在泛型类型上,如果Tclass,那么is 会快得多。如果Tstruct,那么isGetType 快得多,但typeof(T) 比两者都快。Tclass 的情况下,typeof(T) 不是可靠,因为它不同于实际的底层类型t.GetType

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

【讨论】:

实际上,根本不在乎。使用最有意义的。【参考方案3】:

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

is 告诉您对象是否在其类型层次结构中的任何位置实现ClassAGetType() 告诉你派生最多的类型。

不是一回事。

【讨论】:

这很重要,因为在我的情况下,我很肯定它们会返回相同的结果。 @[ilitirit]:它们现在返回相同的结果,但是如果您稍后添加子类,它们将不会 现在优化会让你的代码变得脆弱且难以维护。【参考方案4】:

他们不做同样的事情。如果 obj 是 ClassA 类型或 ClassA 的某个子类,则第一个有效。第二个只会匹配 ClassA 类型的对象。第二个会更快,因为它不需要检查类层次结构。

对于那些想知道原因,但不想阅读is vs typeof中引用的文章的人。

【讨论】:

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

以上是关于is vs typeof的主要内容,如果未能解决你的问题,请参考以下文章

is_valid() vs clean() django 表单

python is_vs_equal.py

Java boolean getter "is" vs "are"

is vs typeof

VS2012 中的 is_directory() 对偶数目录返回 false

NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL: SQL Server