Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ class PersonComparer : IEqualityComparer<Person>
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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="equals2.fs" />
<Compile Include="equals3.fs" />
<Compile Include="equals4.fs" />
<Compile Include="equals_ref.fs" />
<Compile Include="equals_val1.fs" />
<Compile Include="equals_val2.fs" />
<Compile Include="equalsoverride.fs" />
<Compile Include="equalssb1.fs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Point(x, y) =
false

override _.GetHashCode() =
(x <<< 2) ^^^ y
System.HashCode.Combine(x, y)

override _.ToString() =
$"Point({x}, {y})"
Expand All @@ -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})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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
// </Snippet3>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="direct1.fs" />
<Compile Include="shift1.fs" />
<Compile Include="xor1.fs" />
<Compile Include="xor2.fs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -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
// </Snippet3>
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
' </Snippet3>
Original file line number Diff line number Diff line change
Expand Up @@ -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 <xref:System.Tuple`2> 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 <xref:System.HashCode.Combine%2A?displayProperty=nameWithType>. 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":::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading