Прочитать на английском

Поделиться через


HashCode Структура

Определение

Объединяет хэш-код для нескольких значений в один хэш-код.

public struct HashCode
Наследование
HashCode

Примеры

Статические методы в этом классе объединяют хэш-коды по умолчанию не более восьми значений.

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.

Методы экземпляра в этом классе объединяют хэш-коды более восьми значений.

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 объединения нескольких значений (например, полей в структуре или классе) в один хэш-код. Эта структура имеет статические методы и методы экземпляра, которые работают по-разному:

  • Статические методы принимают набор из восьми значений для объединения.
  • Два метода экземпляра работают в режиме потоковой передачи, принимая значения по одному за раз.

Предупреждение

Рекомендуется рассматривать хэш-коды в качестве сведений о реализации, так как реализация может меняться в разных версиях сборки. Не храните хэш-коды, созданные HashCode в сериализованных структурах, например на диске. HashCodeиспользует статически инициализированное случайное начальное значение для применения этой рекомендации. Это означает, что хэш-коды являются детерминированными только в область процесса операционной системы.

Методы

Add<T>(T)

Добавляет одно значение в хэш-код.

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)

Объединяет восемь значений в хэш-код.

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

Объединяет семь значений в хэш-код.

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

Объединяет шесть значений в хэш-код.

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

Объединяет пять значений в хэш-код.

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

Объединяет четыре значения в хэш-код.

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

Объединяет три значения в хэш-код.

Combine<T1,T2>(T1, T2)

Объединяет два значения в хэш-код.

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