Default struct equality is not optimistic for hash based operations
- If a struct does not provide Equal and GetHashCode overrides then the default versions of these methods from System.ValueType are used and they are reflection-based
- The way the CLR is designed, every call to a member defined in System.ValueType or System.Enum types cause a boxing allocation
- Reflection is a powerful tool when used correctly. But it is horrible if it’s used on an application’s hot path.
- Ideally the GetHashCode should combile the hash codes of all the fields
- But the only way to get a hash code of a field in a ValueType method is to use reflection
- So based on point 2, the CLR authors decided to trade speed over the distribution and the default GetHashCode version just returns a hash code of a first non-null field
- If the first field is always the same, the default hash function returns the same value for all the elements
- This effectively transforms a hash set into a linked list with O(N) for insertion and lookup operations
- And the operation that populates the collection becomes O(N^2) (N insertions with O(N) complexity per insertion). and that uses reflection under the hood!
https://benchmarkdotnet.org/articles/guides/getting-started.html