英語で読む

次の方法で共有


HashCode 構造体

定義

複数の値のハッシュ コードを 1 つのハッシュ コードに結合します。

public struct HashCode
継承
HashCode

このクラスの静的メソッドは、 最大 8 つの 値の既定のハッシュ コードを結合します。

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.

重要

ToHashCode() のインスタンス HashCodeごとに最大で 1 回呼び出す必要があります。

このクラスのインスタンス メソッドは、 8 つ以上 の値のハッシュ コードを結合します。

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.

インスタンス メソッドは、特定 IEqualityComparer<T> の実装によって生成されたハッシュ コードも結合します。

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.

構造体は HashCode 値型であるため、他のメソッドに参照渡しする必要があります。

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.

注釈

を使用 HashCode すると、複数の値 (構造体やクラスのフィールドなど) を 1 つのハッシュ コードに結合できます。 この構造体には、動作が異なる静的メソッドとインスタンス メソッドがあります。

  • 静的メソッドは、結合する最大 8 つの値のセットを受け入れます。
  • 2 つのインスタンス メソッドはストリーミング方式で動作し、一度に 1 つずつ値を受け入れます。

警告

実装はアセンブリ バージョン間で変更される可能性があるため、ハッシュ コードを実装の詳細として検討することをお勧めします。 によって HashCode 生成されたハッシュ コードを、ディスク上などのシリアル化された構造体に格納しないでください。 HashCode では、静的に初期化されたランダム シードを使用してこのベスト プラクティスを適用します。つまり、ハッシュ コードはオペレーティング システム プロセスのスコープ内でのみ決定論的です。

メソッド

Add<T>(T)

ハッシュ コードに値を 1 つ追加します。

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

ハッシュ コード関数を提供する型を指定し、ハッシュ コードに単一の値を追加します。

AddBytes(ReadOnlySpan<Byte>)

ハッシュ コードにバイトのスパンを追加します。

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

8 つの値をハッシュ コードに結合します。

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

7 つの値をハッシュ コードに結合します。

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

6 つの値をハッシュ コードに結合します。

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

5 つの値をハッシュ コードに結合します。

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

4 つの値をハッシュ コードに結合します。

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

3 つの値をハッシュ コードに結合します。

Combine<T1,T2>(T1, T2)

2 つの値をハッシュ コードに結合します。

Combine<T1>(T1)

指定した値によって返されるハッシュ コードを拡散します。

Equals(Object)
古い.

このメソッドはサポートされておらず、呼び出すことはできません。

GetHashCode()
古い.

このメソッドはサポートされておらず、呼び出すことはできません。

ToHashCode()

Add を連続して呼び出した後に、最終的なハッシュ コードを計算します。

適用対象

製品 バージョン
.NET Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Standard 2.0, 2.1