【问题标题】:Which is good to use: Object.GetType() == typeof(Type) or Object is Type? [duplicate]哪个好用:Object.GetType() == typeof(Type) 还是 Object is Type? [复制]
【发布时间】:2015-03-04 23:37:38
【问题描述】:

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

Object.GetType() == typeof(Type)

Object is Type

【问题讨论】:

  • 重要的是要理解这两个是不等价的,在处理继承或接口时,一个会返回 false,另一个会返回 true。 Bharadwaj 的链接问题证明了这些差异。
  • 你可以自己实际测试一下。
  • @t3chb0t:测试确实可以给出一个指示,但正如你所看到的,答案也提供了一个解释:is 存在专用的 CIL 指令,而 .GetType() == 是通过执行昂贵的函数调用。

标签: c# performance types


【解决方案1】:

第二个:

Object is Type

stringint 测试了这1'000'000'000 次:

//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# 编译器。

【讨论】:

  • @AmolBavannavar:这是为了让其他用户有机会提出更好的答案。对于这样的问题,很有可能。
  • 您在四分钟内通过测试测量回答了这个问题?太不可思议了 ;-)
  • @AlexeiLevenkov:修改,更好?
  • 公平 - 我添加了评论链接到这个。 ...删除不相关的 cmets 30...29..
  • 这个答案是不是和this一个矛盾,说的正好相反?
猜你喜欢
  • 2012-01-19
  • 2012-08-25
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
  • 2022-08-13
  • 2018-11-03
  • 2021-04-15
相关资源
最近更新 更多