diff --git a/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md b/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md index 312c9719e4292..490322c2f0010 100644 --- a/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md +++ b/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md @@ -81,10 +81,7 @@ class PersonComparer : IEqualityComparer public int GetHashCode(Person person) { if (Object.ReferenceEquals(person, null)) return 0; - int hashFirstName = person.FirstName == null - ? 0 : person.FirstName.GetHashCode(); - int hashLastName = person.LastName.GetHashCode(); - return hashFirstName ^ hashLastName; + return HashCode.Combine(person.FirstName, person.LastName); } } diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/csharp/equals2.cs b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/csharp/equals2.cs index 042751f2634d6..e64ae9a67b8f7 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/csharp/equals2.cs +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/csharp/equals2.cs @@ -30,7 +30,7 @@ public override bool Equals(Object obj) public override int GetHashCode() { - return (x << 2) ^ y; + return HashCode.Combine(x, y); } public override string ToString() @@ -59,7 +59,7 @@ public override bool Equals(Object obj) public override int GetHashCode() { - return (base.GetHashCode() << 2) ^ z; + return HashCode.Combine(base.GetHashCode(), z); } public override String ToString() diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/Project.fsproj b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/Project.fsproj new file mode 100644 index 0000000000000..a045093666eef --- /dev/null +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/Project.fsproj @@ -0,0 +1,19 @@ + + + + Library + net10.0 + + + + + + + + + + + + + + diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/equals2.fs b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/equals2.fs index fdfe5e871a45a..4724fd1968c0a 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/equals2.fs +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/fsharp/equals2.fs @@ -15,7 +15,7 @@ type Point(x, y) = false override _.GetHashCode() = - (x <<< 2) ^^^ y + System.HashCode.Combine(x, y) override _.ToString() = $"Point({x}, {y})" @@ -32,7 +32,7 @@ type Point3D(x, y, z) = false override _.GetHashCode() = - (base.GetHashCode() <<< 2) ^^^ z + System.HashCode.Combine(base.GetHashCode(), z) override _.ToString() = $"Point({x}, {y}, {z})" diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/vb/equals2.vb b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/vb/equals2.vb index 73cadaf12e61c..43dba9f38b9ae 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/vb/equals2.vb +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/Equals/vb/equals2.vb @@ -23,7 +23,7 @@ Class Point1 End Function Public Overrides Function GetHashCode() As Integer - Return (x << 2) Xor y + Return HashCode.Combine(x, y) End Function Public Overrides Function ToString() As String @@ -49,7 +49,7 @@ Class Point3D : Inherits Point1 End Function Public Overrides Function GetHashCode() As Integer - Return (MyBase.GetHashCode() << 2) Xor z + Return HashCode.Combine(MyBase.GetHashCode(), z) End Function Public Overrides Function ToString() As String diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/csharp/xor2.cs b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/csharp/xor2.cs index 0330195634a29..d8ad45dd2f9f0 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/csharp/xor2.cs +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/csharp/xor2.cs @@ -27,7 +27,7 @@ public override bool Equals(Object obj) public override int GetHashCode() { - return Tuple.Create(x, y).GetHashCode(); + return HashCode.Combine(x, y); } } @@ -42,7 +42,8 @@ public static void Main() Console.WriteLine(pt.GetHashCode()); } } -// The example displays the following output: -// 173 -// 269 +// The example displays output similar to the following. +// Note: HashCode.Combine results are not stable across .NET versions. +// 185727722 +// -363254492 // diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/Project.fsproj b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/Project.fsproj new file mode 100644 index 0000000000000..77f3e54624c69 --- /dev/null +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/Project.fsproj @@ -0,0 +1,15 @@ + + + + Library + net10.0 + + + + + + + + + + diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/xor2.fs b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/xor2.fs index c83ecf8770421..1290f982eb0ae 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/xor2.fs +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/fsharp/xor2.fs @@ -14,14 +14,15 @@ type Point(x: int, y: int) = false override _.GetHashCode() = - (x, y).GetHashCode() + System.HashCode.Combine(x, y) let pt = Point(5, 8) printfn $"{pt.GetHashCode()}" let pt2 = Point(8, 5) printfn $"{pt2.GetHashCode()}" -// The example displays the following output: -// 173 -// 269 +// The example displays output similar to the following. +// Note: HashCode.Combine results are not stable across .NET versions. +// 185727722 +// -363254492 // \ No newline at end of file diff --git a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/vb/xor2.vb b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/vb/xor2.vb index 58e5e6afeec69..7a18c7232ed10 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/vb/xor2.vb +++ b/docs/fundamentals/runtime-libraries/snippets/System/Object/GetHashCode/vb/xor2.vb @@ -16,7 +16,7 @@ Public Structure Point End Function Public Overrides Function GetHashCode() As Integer - Return Tuple.Create(x, y).GetHashCode() + Return HashCode.Combine(x, y) End Function End Structure @@ -29,7 +29,8 @@ Public Module Example Console.WriteLine(pt.GetHashCode()) End Sub End Module -' The example displays the following output: -' 173 -' 269 +' The example displays output similar to the following. +' Note: HashCode.Combine results are not stable across .NET versions. +' 185727722 +' -363254492 ' diff --git a/docs/fundamentals/runtime-libraries/system-object-gethashcode.md b/docs/fundamentals/runtime-libraries/system-object-gethashcode.md index 76ca507b4427e..f156c0bfcd0b5 100644 --- a/docs/fundamentals/runtime-libraries/system-object-gethashcode.md +++ b/docs/fundamentals/runtime-libraries/system-object-gethashcode.md @@ -58,13 +58,13 @@ Frequently, a type has multiple data fields that can participate in generating t :::code language="fsharp" source="./snippets/System/Object/GetHashCode/fsharp/xor1.fs" id="Snippet2"::: :::code language="vb" source="./snippets/System/Object/GetHashCode/vb/xor1.vb" id="Snippet2"::: -The previous example returns the same hash code for (n1, n2) and (n2, n1), and so may generate more collisions than are desirable. A number of solutions are available so that hash codes in these cases are not identical. One is to return the hash code of a `Tuple` object that reflects the order of each field. The following example shows a possible implementation that uses the class. Note, though, that the performance overhead of instantiating a `Tuple` object may significantly impact the overall performance of an application that stores large numbers of objects in hash tables. +The previous example returns the same hash code for (n1, n2) and (n2, n1), and so may generate more collisions than are desirable. On .NET 5+, the recommended solution is to use . It avoids the symmetry problem and produces a well-distributed hash code without the overhead of creating a `Tuple` object. :::code language="csharp" source="./snippets/System/Object/GetHashCode/csharp/xor2.cs" id="Snippet3"::: :::code language="fsharp" source="./snippets/System/Object/GetHashCode/fsharp/xor2.fs" id="Snippet3"::: :::code language="vb" source="./snippets/System/Object/GetHashCode/vb/xor2.vb" id="Snippet3"::: -A second alternative solution involves weighting the individual hash codes by left-shifting the hash codes of successive fields by two or more bits. Optimally, bits shifted beyond bit 31 should wrap around rather than be discarded. Since bits are discarded by the left-shift operators in both C# and Visual Basic, this requires creating a left shift-and-wrap method like the following: +In .NET Framework, an alternative is to weight the individual hash codes by left-shifting the hash codes of successive fields by two or more bits. Optimally, bits shifted beyond bit 31 should wrap around rather than be discarded. Since bits are discarded by the left-shift operators in both C# and Visual Basic, this requires creating a left shift-and-wrap method like the following: :::code language="csharp" source="./snippets/System/Object/GetHashCode/csharp/shift1.cs" id="Snippet4"::: :::code language="fsharp" source="./snippets/System/Object/GetHashCode/fsharp/shift1.fs" id="Snippet4"::: diff --git a/docs/visual-basic/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md b/docs/visual-basic/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md index 5157891709bed..4f5fa3b251ad9 100644 --- a/docs/visual-basic/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md +++ b/docs/visual-basic/programming-guide/concepts/covariance-contravariance/using-variance-in-interfaces-for-generic-collections.md @@ -82,11 +82,7 @@ Class PersonComparer Implements IEqualityComparer(Of Person).GetHashCode If person Is Nothing Then Return 0 - Dim hashFirstName = - If(person.FirstName Is Nothing, - 0, person.FirstName.GetHashCode()) - Dim hashLastName = person.LastName.GetHashCode() - Return hashFirstName Xor hashLastName + Return HashCode.Combine(person.FirstName, person.LastName) End Function End Class