【发布时间】:2018-05-15 17:07:02
【问题描述】:
根据这个答案 https://stackoverflow.com/a/8315745/5324847 .Net 应该通过反射或按位比较值类型。但是,如果我们查看这段代码,我们会发现两者都不是(或者两者都不是??)。
//Bitwise test
//if .Net compares bitwise then last line should be false
//if it uses reflections then last line should be true
float a = -0.0f;
float b = 0.0f;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a))); //prints 000128
Console.WriteLine(string.Join("",BitConverter.GetBytes(b))); //prints 0000
Console.WriteLine(a == b); //True
Console.WriteLine(a.Equals(b)); //prints True
//Reflection test
//if .Net compares using reflection then last line should be false
//if it uses bitwise comparsion then last line should be true
a = float.NaN;
b = float.NaN;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a))); //prints 00192255
Console.WriteLine(string.Join("",BitConverter.GetBytes(b))); //prints 00192255
Console.WriteLine(a == b); //False
Console.WriteLine(a.Equals(b)); //prints True
如果我们将变量包装在结构中,.Net 使用按位比较。 证明:
public struct FloatS
{
public float x;
}
public static void Main()
{
//bitwise test
//if .Net compares bitwise then last line should be false
//if it uses reflections then last line should be true
FloatS a = new FloatS();
FloatS b = new FloatS();
a.x = -0.0f;
b.x = 0.0f;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a.x))); //prints 000128
Console.WriteLine(string.Join("",BitConverter.GetBytes(b.x))); //prints 0000
Console.WriteLine(a.x == b.x); //True
Console.WriteLine(a.Equals(b)); //prints False -- this time corectly because it's bitwise comparsion
//Reflection test
//if .Net compares using reflection then last line should be false
//if it uses bitwise comparsion then last line should be true
a.x = float.NaN;
b.x = float.NaN;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a.x))); //prints 00192255
Console.WriteLine(string.Join("",BitConverter.GetBytes(b.x))); //prints 00192255
Console.WriteLine(a.x == b.x); //False
Console.WriteLine(a.Equals(b)); //prints True - also corectly
}
我的假设是 .Net 对原始类型使用 Equals 的不同实现。但这似乎不正确,因为 float 和 struct 类型都可以转换为 System.ValueType。
谁能解释发生了什么?
【问题讨论】:
-
任何值类型都可以提供它自己的相等运算符和 Equals 方法的实现。如果您不这样做,您所描述的是“默认”行为。当然 float 和其他原始类型确实提供了这样的实现。
-
很高兴知道@HansPassant。我刚刚意识到
Console.WriteLine(float.NaN == float.NaN);print false,这对我来说太奇怪了! -
并检查reference source 并不能帮助我理解这种行为:@HansPassant,魔法发生的方法运算符是什么?
-
@GianPaolo 您不会在参考源中找到它,因为当您比较浮点数(或整数等)时 - in 被编译为特殊的
ceqIL 指令(或其他类似的指令,具体取决于上下文) ,而不是实际的==运算符。