哪个好用:Object.GetType()== typeof(Type)或Object是Type?

我想知道哪个语句在Performance Point of View中是否有用

Object.GetType() == typeof(Type) 

要么

 Object is Type 

第二个:

 Object is Type 

string测试这个1’000’000’000次对比int得到:

 //Release 00:00:18.1428040 //Object.GetType() == typeof(Type) 00:00:03.9791070 //Object is Type //Debug 00:00:21.3545510 //Object.GetType() == typeof(Type) 00:00:06.2969510 //Object is Type //Machine specs: //Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz //6 GB RAM memory //Ubuntu 14.04 (OS) //Runtime: Mono JIT compiler version 3.2.8 //Compiler: Mono dmcs //Notes: ran these with some background processes, but the difference in time // is significant enough I guess. 

注意两者之间存在很强的语义差异

  • 等式==检查类型相等:换句话说,如果A : B比相等测试将失败A.GetType() == typeof(B)A is B将成功。
  • 如果对象为null ,则抛出System.NullReferenceException 。 在第二种情况下,它将返回false

从编译器的角度来看,这是相当逻辑的:在第一个变体中,您查询对象的类型。 如果没有真正优化,你首先进行函数调用,然后调用它说它必须返回一个指向类型表的指针。

在第二种情况下,省略了这样的调用:编译器将通过返回类型代码来专门化它。 如果预先知道Type ,它甚至可以对它进行非常快速的测试。

另外请注意,对于一些简单的情况,可以优化Object is Type :例如,因为编译器已经可以导出Object不能/始终是Type

更先进

还可以分析CIL虚拟机源代码,对于第一个变体,这是:

 IL_0000: ldarg.0 IL_0001: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_0006: ldtoken [mscorlib]System.Int32 IL_000b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_0010: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, class [mscorlib]System.Type) IL_0015: ret 

对于第二个变体,这是:

 IL_0000: ldarg.0 IL_0001: isinst [mscorlib]System.Int32 IL_0006: ldnull IL_0007: cgt.un IL_0009: ret 

(你当然可以填写其他类型)。 现在ldarg.0ret只是使用方法的副产品,所以可以忽略它们。

我们看到的是,在第一个变体中,一个显式调用GetType方法,然后调用==运算符。 函数调用通常很昂贵。 在第二个变体中,它会立即检查isinst 。 代码需要更少的字节并使用更便宜的方法。 虽然性能当然取决于运行时环境的实现,但我认为第二种变体在性能上几乎总能胜过第一种变体是相当安全的。

编译器可能可以专门化第一个变体,使其运行与第二个变量一样高效,但Mono C#编译器似乎不会这样做。 可能没有一个可用的C#编译器。