使用哪一个好:Object.GetType() == typeof(Type)还是Object is Type?

16 浏览
0 Comments

使用哪一个好:Object.GetType() == typeof(Type)还是Object is Type?

这个问题已经在此处有答案

类型检查:使用typeof、GetType还是is?

我想知道从性能角度来看哪个语句更有用,是使用

Object.GetType() == typeof(Type)

还是

Object is Type

admin 更改状态以发布 2023年5月25日
0
0 Comments

第二个:

Object is Type

已经用 stringint 进行了1000000000次测试,结果如下:

//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是B将成功。
  • 如果此对象为空,它将引发System.NullReferenceException异常。在第二种情况下,它将返回False

从编译器的角度来看,这是相当正确的:在第一种方式中,您查询对象的类型。如果这并不真正得到优化,在第一个调用中,这一调用将指示必须返回指向类型表的指针。

在第二种情况下,您省略了这些调用:编译器将专门化它通过返回类型代码。并且,如果Type预先已知,它甚至可以找出一种非常快速的测试方式。

此外注意,对于一些平凡的情况,Objects是Type可以被优化:例如,编译器可以推导出对象不能/总是是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#编译器会这样做。

0