Quick example:
using System;
using System.Globalization;
var d1 = new DateTime(2023, 2, 28, 0, 0, 0, DateTimeKind.Unspecified);
var d2 = new DateTime(2023, 2, 28, 0, 0, 0, DateTimeKind.Local);
var foo1 = new Foo { d = d1 };
var foo2 = new Foo { d = d2 };
Console.WriteLine($"d1.Equals(d2): {d1.Equals(d2)}");
Console.WriteLine($"d1.GetHashCode() == d2.GetHashCode(): {d1.GetHashCode() == d2.GetHashCode()}");
Console.WriteLine($"foo1.Equals(foo2): {foo1.Equals(foo2)}");
Console.WriteLine($"foo1.GetHashCode() == foo2.GetHashCode(): {foo1.GetHashCode() == foo2.GetHashCode()}");
struct Foo {
public DateTime d;
}
Prints:
d1.Equals(d2): True
d1.GetHashCode() == d2.GetHashCode(): True
foo1.Equals(foo2): True
foo1.GetHashCode() == foo2.GetHashCode(): False
DateTime intentionally ignores Kind in its Equals and GetHashCode methods. However, it seems that it is not ignored in the GetHashCode methods of a simple struct which contains a DateTime.
My guess is it might be related to this optimization which uses memcmp when all fields are 8 bytes wide (discussed for example here).
However, is it possible that it is used only for GetHashCode and not for Equals? Is it "only" an issue with DateTime or is it more general, e.g. this optimization doesn't check for overriden Equals/GetHashCode?