简体   繁体   English

等于方法的奇怪行为

[英]Strange behavior of Equals method

According to this answer https://stackoverflow.com/a/8315745/5324847 .Net should compare value types by reflection or bitwise. 根据这个答案https://stackoverflow.com/a/8315745/5324847.Net应该通过反射或按位比较值类型。 But if we look at this code we can see it's neither (or both of them at once??). 但是,如果我们看一下这段代码,就会发现两者都不是(或者两者都可以??)。

//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

If we wrap the variable in structure .Net uses bitwise comparsion. 如果我们将变量包装在结构中,.Net将使用按位比较。 Proof: 证明:

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
}

My asumption was that .Net uses difrent implementation of Equals for primitive types. 我的假设是,.Net对基本类型使用Equals的不同实现。 But that seems incorect because both float and struct type can be cast to System.ValueType . 但这似乎是不正确的,因为float和struct类型都可以转换为System.ValueType

Can anybody explain what is happening? 有人可以解释发生了什么吗?

According to ... .NET should compare value types by reflection or bitwise. 根据...,。NET应该通过反射或按位比较值类型。

You're misreading that answer, which is about user-defined value types . 您误解了有关用户定义的值类型的答案。

  • For == , floats are compared using special instructions just for floats. 对于== ,仅针对浮点数使用特殊指令比较浮点数。 Zero and negative zero are equal, NaN equals nothing, not even itself, and so on. 零和负零相等,NaN不等于任何东西,依此类推。

  • Any type can override Equals , and System.Single does so. 任何类型都可以覆盖Equals ,而System.Single可以这样做。 x.Equals(y) on floats has the semantics of (x == y) || (IsNaN(x) && IsNaN(y)) x.Equals(y)的语义为(x == y) || (IsNaN(x) && IsNaN(y)) (x == y) || (IsNaN(x) && IsNaN(y)) . (x == y) || (IsNaN(x) && IsNaN(y)) I do not know for certain why Equals and == were made to have different behaviour, though probably it was to ensure that Equals on floats is an equivalence relation, which is necessary for certain applications such as putting floats into a hash table. 我不确定为什么为什么使Equals==具有不同的行为,尽管可能是要确保float上的Equals是等效关系,这对于某些应用程序(例如将floats放入哈希表中)是必需的。 (UPDATE: My supposition is correct; see comment below.) (更新:我的假设是正确的;请参阅下面的评论。)

If you write a user-defined value type and do not provide your own Equals then you get the default one, which as you note has two big problems: 如果您编写了一个用户定义的值类型而没有提供自己的Equals那么您将获得默认值,这是您注意到的两个大问题:

  • It is sometimes not efficient 有时效率不高
  • A struct that wraps a float does not automatically get float equality behaviour. 包装浮点数的结构不会自动获得浮点数相等行为。 More generally, a struct that wraps a T does not automatically get T equality behaviour. 更一般而言,包装T的结构不会自动获得T相等的行为。

My assumption was that .NET uses different implementation of Equals for primitive types. 我的假设是.NET对原始类型使用不同的Equals实现。 But that seems incorrect because both float and struct type can be cast to System.ValueType. 但这似乎不正确,因为float和struct类型都可以转换为System.ValueType。

This paragraph makes zero sense to me, and so either I am misunderstanding you, or you believe something completely false about inheritance. 本段对我来说没有任何意义,所以我可能误会了您,或者您认为继承完全不正确。 Every type can override Equals . 每种类型都可以覆盖Equals What does that have to do with the fact that user code can box any non-nullable value type? 用户代码可以将任何非空值类型装箱,这与事实有什么关系? I don't see the connection between your two sentences, and the fact that you believe there is one indicates that someone has a wrong belief here. 我看不到您的两个句子之间的联系,并且您相信其中一个句子的事实表明有人在这里有错误的信念。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM