Double的“==”运算符的定义?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (19)

进入.NET Framework类的源代码double并发现==是:

public static bool operator ==(Double left, Double right) {
    return left == right;
}

同样的逻辑适用于每一个接线员。

  • 这样的定义有什么意义?
  • 它是如何工作的?
  • 为什么不创建一个无限递归呢?
提问于
用户回答回答于

实际上,编译器将将==运算符变成aceq所提到的运算符将不会被调用。

在源代码中使用运算符的原因可能是因为它可以从C#以外的语言调用,而C#语言不会将其转换为CEQ直接(或通过反射)调用。

实际上,如果通过反射调用运算符,则可以看到调用了运算符(而不是CEQ,而且显然不是无限递归的(因为程序按预期结束):

double d1 = 1.1;
double d2 = 2.2;

MethodInfo mi = typeof(Double).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public );

bool b = (bool)(mi.Invoke(null, new object[] {d1,d2}));

结果IL(由LinqPad 4汇编):

IL_0000:  nop         
IL_0001:  ldc.r8      9A 99 99 99 99 99 F1 3F 
IL_000A:  stloc.0     // d1
IL_000B:  ldc.r8      9A 99 99 99 99 99 01 40 
IL_0014:  stloc.1     // d2
IL_0015:  ldtoken     System.Double
IL_001A:  call        System.Type.GetTypeFromHandle
IL_001F:  ldstr       "op_Equality"
IL_0024:  ldc.i4.s    18 
IL_0026:  call        System.Type.GetMethod
IL_002B:  stloc.2     // mi
IL_002C:  ldloc.2     // mi
IL_002D:  ldnull      
IL_002E:  ldc.i4.2    
IL_002F:  newarr      System.Object
IL_0034:  stloc.s     04 // CS$0$0000
IL_0036:  ldloc.s     04 // CS$0$0000
IL_0038:  ldc.i4.0    
IL_0039:  ldloc.0     // d1
IL_003A:  box         System.Double
IL_003F:  stelem.ref  
IL_0040:  ldloc.s     04 // CS$0$0000
IL_0042:  ldc.i4.1    
IL_0043:  ldloc.1     // d2
IL_0044:  box         System.Double
IL_0049:  stelem.ref  
IL_004A:  ldloc.s     04 // CS$0$0000
IL_004C:  callvirt    System.Reflection.MethodBase.Invoke
IL_0051:  unbox.any   System.Boolean
IL_0056:  stloc.3     // b
IL_0057:  ret 

有趣的是,对于积分类型,相同的运算符不存在(无论是在引用源中还是通过反射),只有SingleDoubleDecimalString,和DateTime这就否定了我的理论,即他们的存在是为了从其他语言中被召唤出来。显然,在没有这些运算符的情况下,可以在其他语言中将两个整数等同起来,所以我们回到“为什么它们存在于double“?

用户回答回答于

这里的主要困惑是,假设所有.NET库(在本例中是扩展的数字库,即BCL的一部分是用标准C#编写的。情况并不总是如此,不同的语言有不同的规则。

在标准C#中,由于操作符重载解析的工作方式,看到的代码段将导致堆栈溢出。然而,代码实际上并不在标准C#中,它基本上使用了C#编译器的无文档特性。它不调用操作符,而是发出以下代码:

ldarg.0
ldarg.1
ceq
ret

就是这样:)没有100%等效的C#代码--这在C#中是不可能的你自己的类型。

即使这样,在编译C#代码时也不会使用实际的运算符--编译器会执行一系列优化,例如在本例中,它将替换op_Equality用简单的方式打电话ceq。再说一次,你不能在你自己的DoubleEx结构-这是编译器的魔力。

在.NET中,这当然不是唯一的情况--有许多代码是无效的,标准C#。原因通常是:(A)编译器黑客和(B)另一种语言,有奇怪的(C)运行时黑客(我在看你,Nullable!)。

由于Roslyn C#编译器是Oepn源代码,我实际上可以指出确定重载解析的位置:

解析所有二进制运算符的位置。

内禀运算符的“快捷键”

当你看快捷键时,你会看到,在内在的双操作符中,双和双的相等,绝不可能在实际中==在类型上定义的运算符。.NET类型系统必须假装Double和其他类型一样,但C#不-double是C#中的原语。

扫码关注云+社区