【问题标题】:Difference between the "ceq" MSIL command and object.InternalEquals“ceq” MSIL 命令和 object.InternalEquals 之间的区别
【发布时间】:2011-03-08 08:17:46
【问题描述】:

我在 ILDASM 和 Reflector 中挖掘发现:

  1. == 编译为“ceq”MSIL 命令
  2. object.Equals 保持原样
  3. object.Equals 调用 object.InternalEquals

This 问题向我展示了如何找出 InternalEquals 的实现方式,即在 .cpp 类中(或其他任何地方,在 CLR 中的某个位置)。

我的问题是:

ceq 变成了什么?不同 .cpp 类中的另一种方法? IE。它们是完全不同的代码片段?那么虽然 == 和 Equals 的默认行为看起来是一样的,但它是不同的代码?

【问题讨论】:

标签: c# equals cil


【解决方案1】:

== 运算符并不总是被翻译成 ceq。一个类型可以用 operator==() 重载它。例如,System.Decimal 这样做,它重载了所有运算符,因为它们的实现是不平凡的,并且抖动没有类型的特殊知识(编译器有)。

您将使用 Reflector 作为 Decimal.op_Equality() 方法找到它。这将引导您进入 FCallCompare,这是一种使用 MethodImplOptions.InternalCall 属性的方法。这类方法比较特殊,jitter对它们有秘密的了解。您可以通过 Rotor 中的 clr/src/vm/ecall.cpp 源代码文件找到它们的实现。它包含所有内部调用函数的表,jitter 通过方法名称查找表条目。然后将表中提供的相应C++函数的地址编译到调用指令中。请注意,自转子发布以来,函数名称已更改,搜索 FCallAdd,它是表中的下一个条目。这会将您带到 COMDecimal::Compare。这会将您带到 comdecimal.cpp 源代码文件。

x86 和 x64 抖动知道如何将 ceq 操作码直接转换为机器码,而不需要辅助函数,它会内联生成本机机器指令。实际生成的代码取决于要比较的值的类型。而目标,x64 jitter 使用 SSE 指令,x86 使用 FPU 指令来比较浮点值。当然,其他抖动会以不同的方式实现它们。

像 Object.InternalEquals() 这样的辅助函数也是一个内部方法,就像 FCallCompare 一样。您将使用相同的策略来找到实现。

【讨论】:

  • 现在这就是我想要的。详细说明。再一次感谢你。这会让我安静几天:)。
  • 我希望我可以投票/接受两次。说真的,很难找到一个起点,找不到答案让我抓狂。
  • 奇怪,你在 SO 上似乎没有太多问题得到答案 :)
  • 是的,对不起,我不是说我不能在这里得到答案,我非常感谢所有回复。我的意思是,我通常只有在经历了几个小时的痛苦无法自己解决之后才在这里发帖。因此,当有人以详细、洞察力和真正的知识回答时,就意味着很多。
【解决方案2】:

您看到ceq 是因为没有重载== - 它正在进行直接引用比较。为此,它所要做的就是直接比较堆栈中的两个数字;这是它可以做的最快的事情。

object.Equals 不明确;有两个;

x.Equals(y) 是一个虚方法,因此很可能被覆盖。根据类型,将发出虚拟调用、静态调用或受限调用,可能有自定义实现。

object.Equals(x,y) 是一个静态方法,它首先检查空值; 2 个空值 = 真,1 个空值 = 假,0 个空值 - 调用 x.Equals(y)。

但是要专注于这个问题,它是 逻辑上 a == on native ints;在大多数 JIT 中,我希望这仍然是针对两种整数类型(可能是指针)的 ==,但是 JIT 会有所不同(或者实际上可能甚至不存在 - MF 是一个解释器)。

【讨论】:

  • 抱歉耽搁了,谢谢。我很感激花时间来解释。重新模棱两可;抱歉,我的意思是实例 Equals 方法。我的问题是试图了解为什么有两种不同的方法来进行相等检查,在不同的地方(在 CLR 中?)实现,一种默认编译为 msil 指令,另一种保持调用默认是一个外部方法,两者都可以被覆盖....
  • @JM == 可以重载,但不能被覆盖;这是一个很大的区别 - 静态分析和多态性之间。
  • 是的,搞错了,可能是因为已经过了午夜一刻钟,但这并不是一个很好的借口:)。尴尬。谢谢你指出。我正在编辑我的评论:)
  • 除非看起来我不能......哦,好吧。
【解决方案3】:

是的,它们运行不同的代码。

  • Equals 是一个实例方法。
  • == 是一个静态运算符。

两者都可以为自定义类型重新定义。

【讨论】:

  • 感谢您花时间回答。我知道 Equals 是一个实例方法,而 == 是一个运算符。我不明白的是默认实现之间的区别,即“ceq”调用和对“object.InternalEquals”的调用不同,以及为什么首先有两种方法......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-09
  • 2019-07-19
  • 1970-01-01
  • 2015-04-25
  • 2016-07-03
  • 1970-01-01
  • 2018-03-13
相关资源
最近更新 更多