Optimize Uri.GetHashCode by MihaZupan · Pull Request #32713 · dotnet/runtime (original) (raw)
To expand a little bit on what I said above, the only required relationship between object.Equals
and object.GetHashCode
is as follows.
Object.Equals(a, b) ⇒ a.GetHashCode() == a.GetHashCode() StringComparer.FromComparison(comparison).Equals(a, b) ⇒ a.GetHashCode(comparison) == b.GetHashCode(comparison)
And the contrapositives:
a.GetHashCode() != b.GetHashCode() ⇒ !Object.Equals(a, b) a.GetHashCode(comparison) != b.GetHashCode(comparison) ⇒ !StringComparer.FromComparison(comparison).Equals(a, b)
If you have a call to someString.ToLowerInvariant().GetHashCode()
, we would expect to see it paired with the expression stringA.ToLowerInvariant() == stringB.ToLowerInvariant()
at some point. Similarly, if you have a call to someString.GetHashCode(StringComparison.OrdinalIgnoreCase)
, we would expect to see it paired with the expression string.Equals(stringA, stringB, StringComparison.OrdinalIgnoreCase)
at some point.
Importantly, these two expressions do not have the same behavior. Converting two strings to lowercase and checking them for equality is not the same as checking the two strings for equality using an OrdinalIgnoreCase
comparison.
For example depending on operating system and environmental configuration:
"ς".ToLowerInvariant() == "σ".ToLowerInvariant(); // currently always FALSE across all supported OSes string.Equals("ς", "σ", StringComparison.OrdinalIgnoreCase); // may return TRUE depending on OS