That's why it's better to code your own Equals() and GetHashCode() methods in these cases. The task is pretty much straightforward - just compare those fields and properties, that define equality, in Equals(), and XOR their shifted values (or numeric representations of their values) in GetHashCode():
public override bool Equals(object obj) { Nullable<MyType> other = obj as Nullable<MyType>; return other != null && this.X == other.Value.X && this.Y == other.Value.Y; } public override int GetHashCode() { return (this.X * 31) ^ this.Y; }
I recently was asked to tune some code, and replaced several nested loops with dictionary lookups - only to find out that this was not as fast as I had expected, due to structs being applied as dictionary keys. Provided my own Equals() and GetHashCode() implementations, and voila - ten-fold speedup!