Equals method behavior change for NaN

The Equals(T other) instance method for the following types was updated to meet the IEquatable<T> implementation requirements. As a result, the method now correctly handles NaN. This change ensures the types can correctly be used alongside GetHashCode, Dictionary<TKey,TValue>, and other hash sets.

Previous behavior

Previously, the Equals(T other) instance method followed the IEEE 754 requirements and deferred to the == implementation. This meant that NaN != NaN, even when the two NaN are bitwise identical.

For example:

float f = float.NaN;
Console.WriteLine(f == f);         // False
Console.WriteLine(f.Equals(f));   // True

While for several of the listed types:

Vector2 v = new Vector2(float.NaN);
Console.WriteLine(v == v);        // False
Console.WriteLine(v.Equals(v));   // False

This is problematic because using one of these types as a key in a dictionary meant that the key could never be resolved:

Vector2 v = new Vector2(float.NaN);
var s = new HashSet<Vector2>();
s.Add(v);
Console.WriteLine(s.Contains(v)); // False

New behavior

The behavior is now the same as for the primitive floating-point types, which is that the == and != methods continue to follow the IEEE 754 requirements where NaN != NaN. But the Equals(T other) instance methods follow the IEquatable<T> requirements so that NaN.Equals(NaN).

For example (no change):

float f = float.NaN;
Console.WriteLine(f == f);         // False
Console.WriteLine(f.Equals(f));   // True

While for several of the listed types (the second line now prints True):

Vector2 v = new Vector2(float.NaN);
Console.WriteLine(v == v);        // False
Console.WriteLine(v.Equals(v));   // True

And when used in some hash set (the output now prints True):

Vector2 v = new Vector2(float.NaN);
var s = new HashSet<Vector2>();
s.Add(v);
Console.WriteLine(s.Contains(v)); // True

Version introduced

.NET 7

Type of breaking change

This change can affect binary compatibility.

Reason for change

The previous implementation did not meet the implementation requirements of IEquatable<T> or object.Equals(object obj). This resulted in the affected types not being usable in hash sets or with GetHashCode.

If you prefer the previous behavior, switch to using == or != instead of Equals(T other).

Affected APIs