由于某种原因,我偷偷进入类Double
的.NET Framework源代码,发现==
的声明是:
public static bool operator ==(Double left, Double right) {
return left == right;
}
同样的逻辑适用于every运算符.
- 这样的定义有什么意义?
- 它是如何工作的?
- 为什么它不创建一个无限递归呢?
由于某种原因,我偷偷进入类Double
的.NET Framework源代码,发现==
的声明是:
public static bool operator ==(Double left, Double right) {
return left == right;
}
同样的逻辑适用于every运算符.
实际上,编译器会将==
运算符转换为ceq
IL代码,并且不会调用您提到的运算符.
源代码中使用运算符的原因很可能是因为它可以从C#以外的语言调用,而C#不会直接(或通过反射)将其转换为CEQ
调用.运算符will的代码within可以编译为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
有趣的是,积分类型不存在相同的运算符(无论是在参考源中还是通过反射),只有Single
、Double
、Decimal
、String
和DateTime
,这推翻了我的理论,即它们的存在是为了从其他语言调用.显然,在其他语言中,如果没有这些运算符,你可以将两个整数等同起来,所以我们回到问题"double
为什么存在它们"?