Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

HashCode Struct

Definition

Namespace:
System
Assemblies:
netstandard.dll, System.Runtime.dll
Assembly:
System.Runtime.dll
Assembly:
netstandard.dll
Source:
HashCode.cs
Source:
HashCode.cs
Source:
HashCode.cs
Source:
HashCode.cs
Source:
HashCode.cs

Important

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Combines the hash code for multiple values into a single hash code.

public value class HashCode
public struct HashCode
type HashCode = struct
Public Structure HashCode
Inheritance
HashCode

Examples

The static methods in this class combine the default hash codes of up to eight values.

using System;
using System.Collections.Generic;

public struct OrderOrderLine : IEquatable<OrderOrderLine>
{
 public int OrderId { get; }
 public int OrderLineId { get; }

 public OrderOrderLine(int orderId, int orderLineId) => (OrderId, OrderLineId) = (orderId, orderLineId);

 public override bool Equals(object obj) => obj is OrderOrderLine o && Equals(o);

 public bool Equals(OrderOrderLine other) => OrderId == other.OrderId && OrderLineId == other.OrderLineId;

 public override int GetHashCode() => HashCode.Combine(OrderId, OrderLineId);
}

class Program
{
 static void Main(string[] args)
 {
 var set = new HashSet<OrderOrderLine>
 {
 new OrderOrderLine(1, 1),
 new OrderOrderLine(1, 1),
 new OrderOrderLine(1, 2)
 };

 Console.WriteLine($"Item count: {set.Count}.");
 }
}
// The example displays the following output:
// Item count: 2.
open System
open System.Collections.Generic

[<Struct; CustomEquality; NoComparison>]
type OrderOrderLine(orderId: int, orderLineId: int) =
 member _.OrderId = orderId
 member _.OrderLineId = orderLineId

 override _.GetHashCode() = 
 HashCode.Combine(orderId, orderLineId)

 override this.Equals(obj) =
 match obj with
 | :? OrderOrderLine as o -> (this :> IEquatable<_>).Equals o
 | _ -> false

 interface IEquatable<OrderOrderLine> with
 member _.Equals(other: OrderOrderLine) = 
 orderId = other.OrderId && orderLineId = other.OrderLineId

let set =
 HashSet<OrderOrderLine> [ OrderOrderLine(1, 1); OrderOrderLine(1, 1); OrderOrderLine(1, 2) ]
printfn $"Item count: {set.Count}."

// The example displays the following output:
// Item count: 2.
Public Structure OrderOrderLine
 Implements IEquatable(Of OrderOrderLine)

 Public ReadOnly Property OrderId As Integer
 Public ReadOnly Property OrderLineId As Integer

 Public Sub New(ByVal orderId As Integer, ByVal orderLineId As Integer)
 Me.OrderId = orderId
 Me.OrderLineId = orderLineId
 End Sub

 Public Overrides Function Equals(obj As Object) As Boolean
 Return (TypeOf obj Is OrderOrderLine) AndAlso Equals(DirectCast(obj, OrderOrderLine))
 End Function

 Public Overloads Function Equals(other As OrderOrderLine) As Boolean Implements IEquatable(Of OrderOrderLine).Equals
 Return OrderId = other.OrderId AndAlso
 OrderLineId = other.OrderLineId
 End Function

 Public Overrides Function GetHashCode() As Integer
 Return HashCode.Combine(OrderId, OrderLineId)
 End Function

End Structure

Module Program

 Sub Main(args As String())
 Dim hashSet As HashSet(Of OrderOrderLine) = New HashSet(Of OrderOrderLine)
 hashSet.Add(New OrderOrderLine(1, 1))
 hashSet.Add(New OrderOrderLine(1, 1))
 hashSet.Add(New OrderOrderLine(1, 2))
 Console.WriteLine($"Item count: {hashSet.Count}")
 End Sub

End Module
' The example displays the following output:
' Item count: 2.

Important

ToHashCode() must be called at most once per instance of HashCode.

The instance methods in this class combine the hash codes of more than eight values.

using System;
using System.Collections.Generic;

public struct Path : IEquatable<Path>
{
 public IReadOnlyList<string> Segments { get; }

 public Path(params string[] segments) => Segments = segments;

 public override bool Equals(object obj) => obj is Path o && Equals(o);

 public bool Equals(Path other)
 {
 if (ReferenceEquals(Segments, other.Segments)) return true;
 if (Segments is null || other.Segments is null) return false;
 if (Segments.Count != other.Segments.Count) return false;

 for (var i = 0; i < Segments.Count; i++)
 {
 if (!string.Equals(Segments[i], other.Segments[i]))
 return false;
 }

 return true;
 }

 public override int GetHashCode()
 {
 var hash = new HashCode();

 for (var i = 0; i < Segments?.Count; i++)
 hash.Add(Segments[i]);

 return hash.ToHashCode();
 }
}

class Program
{
 static void Main(string[] args)
 {
 var set = new HashSet<Path>
 {
 new Path("C:", "tmp", "file.txt"),
 new Path("C:", "tmp", "file.txt"),
 new Path("C:", "tmp", "file.tmp")
 };

 Console.WriteLine($"Item count: {set.Count}.");
 }
}
// The example displays the following output:
// Item count: 2.
open System
open System.Collections.Generic

[<Struct; CustomEquality; NoComparison>]
type Path([<ParamArray>]segments: string[]) = 
 member _.Segments = 
 Array.AsReadOnly segments

 override this.Equals(obj) =
 match obj with
 | :? Path as o -> (this :> IEquatable<_>).Equals(o)
 | _ -> false

 interface IEquatable<Path> with
 member this.Equals(other: Path) =
 Object.ReferenceEquals(this.Segments, other.Segments) ||
 not (isNull this.Segments) && 
 not (isNull other.Segments) &&
 this.Segments.Count = other.Segments.Count &&
 Seq.forall2 (=) this.Segments other.Segments 

 override this.GetHashCode() =
 let hash = HashCode()

 for i = 0 to this.Segments.Count - 1 do
 hash.Add this.Segments[i]
 hash.ToHashCode()

let set = 
 HashSet<Path> [
 Path("C:", "tmp", "file.txt")
 Path("C:", "tmp", "file.tmp")
 Path("C:", "tmp", "file.txt") ]
 
printfn $"Item count: {set.Count}."

// The example displays the following output:
// Item count: 2.
Public Structure Path
 Implements IEquatable(Of Path)

 Public ReadOnly Property Segments As IReadOnlyList(Of String)

 Public Sub New(ParamArray ByVal segments() As String)
 Me.Segments = segments
 End Sub

 Public Overrides Function Equals(obj As Object) As Boolean
 Return (TypeOf obj Is Path) AndAlso Equals(DirectCast(obj, Path))
 End Function

 Public Overloads Function Equals(other As Path) As Boolean Implements IEquatable(Of Path).Equals
 If ReferenceEquals(Segments, other.Segments) Then Return True
 If Segments Is Nothing OrElse other.Segments Is Nothing Then Return False
 If Segments.Count <> other.Segments.Count Then Return False

 For i As Integer = 0 To Segments.Count - 1
 If Not String.Equals(Segments(i), other.Segments(i)) Then Return False
 Next

 Return True
 End Function

 Public Overrides Function GetHashCode() As Integer
 Dim hash As HashCode = New HashCode()

 For i As Integer = 0 To Segments?.Count - 1
 hash.Add(Segments(i))
 Next

 Return hash.ToHashCode()
 End Function

End Structure

Module Program

 Sub Main(args As String())
 Dim hashSet As HashSet(Of Path) = New HashSet(Of Path) From {
 New Path("C:", "tmp", "file.txt"),
 New Path("C:", "tmp", "file.txt"),
 New Path("C:", "tmp", "file.tmp")
 }
 Console.WriteLine($"Item count: {hashSet.Count}.")
 End Sub

End Module
' The example displays the following output:
' Item count: 2.

The instance methods also combine the hash codes produced by a specific IEqualityComparer<T> implementation.

using System;
using System.Collections.Generic;

public struct Path : IEquatable<Path>
{
 public IReadOnlyList<string> Segments { get; }

 public Path(params string[] segments) => Segments = segments;

 public override bool Equals(object obj) => obj is Path o && Equals(o);

 public bool Equals(Path other)
 {
 if (ReferenceEquals(Segments, other.Segments)) return true;
 if (Segments is null || other.Segments is null) return false;
 if (Segments.Count != other.Segments.Count) return false;

 for (var i = 0; i < Segments.Count; i++)
 {
 if (!string.Equals(Segments[i], other.Segments[i], StringComparison.OrdinalIgnoreCase))
 return false;
 }

 return true;
 }

 public override int GetHashCode()
 {
 var hash = new HashCode();

 for (var i = 0; i < Segments?.Count; i++)
 hash.Add(Segments[i], StringComparer.OrdinalIgnoreCase);

 return hash.ToHashCode();
 }
}

class Program
{
 static void Main(string[] args)
 {
 var set = new HashSet<Path>
 {
 new Path("C:", "tmp", "file.txt"),
 new Path("C:", "TMP", "file.txt"),
 new Path("C:", "tmp", "FILE.TXT")
 };

 Console.WriteLine($"Item count: {set.Count}.");
 }
}
// The example displays the following output:
// Item count: 1.
open System
open System.Collections.Generic

[<Struct; CustomEquality; NoComparison>]
type Path([<ParamArray>]segments: string[]) =
 member _.Segments = 
 Array.AsReadOnly segments

 override this.Equals(obj) =
 match obj with
 | :? Path as o -> (this :> IEquatable<_>).Equals(o)
 | _ -> false

 interface IEquatable<Path> with
 member this.Equals(other: Path) =
 Object.ReferenceEquals(this.Segments, other.Segments) ||
 not (isNull this.Segments) && 
 not (isNull other.Segments) &&
 this.Segments.Count = other.Segments.Count &&
 Seq.forall2 (fun x y -> String.Equals(x, y, StringComparison.OrdinalIgnoreCase)) this.Segments other.Segments 

 override this.GetHashCode() =
 let hash = HashCode()

 for i = 0 to this.Segments.Count - 1 do
 hash.Add(this.Segments[i], StringComparer.OrdinalIgnoreCase)
 hash.ToHashCode()

let set = 
 HashSet<Path> [
 Path("C:", "tmp", "file.txt")
 Path("C:", "tmp", "file.tmp")
 Path("C:", "tmp", "file.txt") ]

printfn $"Item count: {set.Count}."

// The example displays the following output:
// Item count: 1.
Public Structure Path
 Implements IEquatable(Of Path)

 Public ReadOnly Property Segments As IReadOnlyList(Of String)

 Public Sub New(ParamArray ByVal segments() As String)
 Me.Segments = segments
 End Sub

 Public Overrides Function Equals(obj As Object) As Boolean
 Return (TypeOf obj Is Path) AndAlso Equals(DirectCast(obj, Path))
 End Function

 Public Overloads Function Equals(other As Path) As Boolean Implements IEquatable(Of Path).Equals
 If ReferenceEquals(Segments, other.Segments) Then Return True
 If Segments Is Nothing OrElse other.Segments Is Nothing Then Return False
 If Segments.Count <> other.Segments.Count Then Return False

 For i As Integer = 0 To Segments.Count - 1
 If Not String.Equals(Segments(i), other.Segments(i), StringComparison.OrdinalIgnoreCase) Then Return False
 Next

 Return True
 End Function

 Public Overrides Function GetHashCode() As Integer
 Dim hash As HashCode = New HashCode()

 For i As Integer = 0 To Segments?.Count - 1
 hash.Add(Segments(i), StringComparer.OrdinalIgnoreCase)
 Next

 Return hash.ToHashCode()
 End Function
 
End Structure

Module Program

 Sub Main(args As String())
 Dim hashSet As HashSet(Of Path) = New HashSet(Of Path) From {
 New Path("C:", "tmp", "file.txt"),
 New Path("C:", "TMP", "file.txt"),
 New Path("C:", "tmp", "FILE.TXT")
 }
 Console.WriteLine($"Item count: {hashSet.Count}.")
 End Sub

End Module
' The example displays the following output:
' Item count: 1.

The HashCode structure must be passed by-reference to other methods, as it is a value type.

using System;
using System.Collections.Generic;

public struct Path : IEquatable<Path>
{
 public IReadOnlyList<string> Segments { get; }

 public Path(params string[] segments) => Segments = segments;

 public override bool Equals(object obj) => obj is Path o && Equals(o);

 public bool Equals(Path other)
 {
 if (ReferenceEquals(Segments, other.Segments)) return true;
 if (Segments is null || other.Segments is null) return false;
 if (Segments.Count != other.Segments.Count) return false;

 for (var i = 0; i < Segments.Count; i++)
 {
 if (!PlatformUtils.PathEquals(Segments[i], other.Segments[i]))
 return false;
 }

 return true;
 }

 public override int GetHashCode()
 {
 var hash = new HashCode();

 for (var i = 0; i < Segments?.Count; i++)
 PlatformUtils.AddPath(ref hash, Segments[i]);

 return hash.ToHashCode();
 }
}

internal static class PlatformUtils
{
 public static bool PathEquals(string a, string b) => string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
 public static void AddPath(ref HashCode hash, string path) => hash.Add(path, StringComparer.OrdinalIgnoreCase);
}

class Program
{
 static void Main(string[] args)
 {
 var set = new HashSet<Path>
 {
 new Path("C:", "tmp", "file.txt"),
 new Path("C:", "TMP", "file.txt"),
 new Path("C:", "tmp", "FILE.TXT")
 };

 Console.WriteLine($"Item count: {set.Count}.");
 }
}
// The example displays the following output:
// Item count: 1.
open System
open System.Collections.Generic

module PlatformUtils =
 let pathEquals a b = String.Equals(a, b, StringComparison.OrdinalIgnoreCase)
 let addPath (hash: byref<HashCode>) path = hash.Add(path, StringComparer.OrdinalIgnoreCase)

[<Struct; CustomEquality; NoComparison>]
type Path([<ParamArray>]segments: string[]) =
 member _.Segments = 
 Array.AsReadOnly segments

 override this.Equals(obj) =
 match obj with
 | :? Path as o -> (this :> IEquatable<_>).Equals(o)
 | _ -> false

 interface IEquatable<Path> with
 member this.Equals(other: Path) =
 Object.ReferenceEquals(this.Segments, other.Segments) ||
 not (isNull this.Segments) && 
 not (isNull other.Segments) &&
 this.Segments.Count = other.Segments.Count &&
 Seq.forall2 PlatformUtils.pathEquals this.Segments other.Segments 

 override this.GetHashCode() =
 let mutable hash = HashCode()

 for i = 0 to this.Segments.Count - 1 do
 PlatformUtils.addPath &hash this.Segments[i]
 hash.ToHashCode()


let set =
 HashSet<Path> [
 Path("C:", "tmp", "file.txt")
 Path("C:", "TMP", "file.txt")
 Path("C:", "tmp", "FILE.TXT") ]

printfn $"Item count: {set.Count}."

// The example displays the following output:
// Item count: 1.
Public Structure Path
 Implements IEquatable(Of Path)

 Public ReadOnly Property Segments As IReadOnlyList(Of String)

 Public Sub New(ParamArray ByVal segments() As String)
 Me.Segments = segments
 End Sub

 Public Overrides Function Equals(obj As Object) As Boolean
 Return (TypeOf obj Is Path) AndAlso Equals(DirectCast(obj, Path))
 End Function

 Public Overloads Function Equals(other As Path) As Boolean Implements IEquatable(Of Path).Equals
 If ReferenceEquals(Segments, other.Segments) Then Return True
 If Segments Is Nothing OrElse other.Segments Is Nothing Then Return False
 If Segments.Count <> other.Segments.Count Then Return False

 For i As Integer = 0 To Segments.Count - 1
 If Not PathEquals(Segments(i), other.Segments(i)) Then Return False
 Next

 Return True
 End Function

 Public Overrides Function GetHashCode() As Integer
 Dim hash As HashCode = New HashCode()

 For i As Integer = 0 To Segments?.Count - 1
 AddPath(hash, Segments(i))
 Next

 Return hash.ToHashCode()
 End Function
 
End Structure

Friend Module PlatformUtils

 Public Function PathEquals(ByVal a As String, ByVal b As String) As Boolean
 Return String.Equals(a, b, StringComparison.OrdinalIgnoreCase)
 End Function

 Public Sub AddPath(ByRef hash As HashCode, ByVal path As String)
 hash.Add(path, StringComparer.OrdinalIgnoreCase)
 End Sub

End Module

Module Program

 Sub Main(args As String())
 Dim hashSet As HashSet(Of Path) = New HashSet(Of Path) From {
 New Path("C:", "tmp", "file.txt"),
 New Path("C:", "TMP", "file.txt"),
 New Path("C:", "tmp", "FILE.TXT")
 }
 Console.WriteLine($"Item count: {hashSet.Count}.")
 End Sub

End Module
' The example displays the following output:
' Item count: 1.

Remarks

You can use HashCode to combine multiple values (for example, fields on a structure or class) into a single hash code. This structure has static and instance methods that operate differently:

  • The static methods accept a set of up to eight values to combine.
  • Two instance methods operate in a streaming fashion, accepting values one at a time.

Warning

It's best-practice to consider hash codes as an implementation detail, as the implementation may change across assembly versions. Do not store hash codes produced by HashCode in serialized structures, for example, on-disk. HashCode uses a statically initialized random seed to enforce this best practice, meaning that the hash codes are only deterministic within the scope of an operating system process.

Methods

Name Description
Add<T>(T, IEqualityComparer<T>)

Adds a single value to the hash code, specifying the type that provides the hash code function.

Add<T>(T)

Adds a single value to the hash code.

AddBytes(ReadOnlySpan<Byte>)

Adds a span of bytes to the hash code.

Combine<T1,T2,T3,T4,T5,T6,T7,T8>(T1, T2, T3, T4, T5, T6, T7, T8)

Combines eight values into a hash code.

Combine<T1,T2,T3,T4,T5,T6,T7>(T1, T2, T3, T4, T5, T6, T7)

Combines seven values into a hash code.

Combine<T1,T2,T3,T4,T5,T6>(T1, T2, T3, T4, T5, T6)

Combines six values into a hash code.

Combine<T1,T2,T3,T4,T5>(T1, T2, T3, T4, T5)

Combines five values into a hash code.

Combine<T1,T2,T3,T4>(T1, T2, T3, T4)

Combines four values into a hash code.

Combine<T1,T2,T3>(T1, T2, T3)

Combines three values into a hash code.

Combine<T1,T2>(T1, T2)

Combines two values into a hash code.

Combine<T1>(T1)

Diffuses the hash code returned by the specified value.

Equals(Object)
Obsolete.

This method is not supported and should not be called.

GetHashCode()
Obsolete.

This method is not supported and should not be called.

ToHashCode()

Calculates the final hash code after consecutive Add invocations.

Applies to


Feedback

Was this page helpful?