简体   繁体   中英

Strange behavior of Equals method

According to this answer https://stackoverflow.com/a/8315745/5324847 .Net should compare value types by reflection or bitwise. 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. 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. But that seems incorect because both float and struct type can be cast to System.ValueType .

Can anybody explain what is happening?

According to ... .NET should compare value types by reflection or bitwise.

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.

  • Any type can override Equals , and System.Single does so. x.Equals(y) on floats has the semantics of (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. (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:

  • 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.

My assumption was that .NET uses different implementation of Equals for primitive types. But that seems incorrect because both float and struct type can be cast to 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 . 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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