如何在实例上创建的哈希

本文关键字:创建 哈希 实例 | 更新日期: 2023-09-27 18:20:24

我有一个产品类,

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ModelNumber { get; set; }
    public string Sku { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double NewPrice { get; set; }
}

我正在将此类保存在数据库表中。但我还需要将每个对象的散列保存在数据库表中,以便进行更改跟踪。我要找的是

        var p1 = new Product{
            Id =2,
            Name = "1",
            ModelNumber = "4"
        };
        var p2 = new Product
        {
            Id = 2,
            Name = "1",
            ModelNumber = "4"
        }; 
        var hashOfp1 = Hash(p1);
        var hashOfp2 = Hash(p2);
        // This should return true because both objects have same values
        if(hashOfp1  == hashOfp2){
        }

如何在实例上创建的哈希

这类事情的好处是:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ModelNumber { get; set; }
    public string Sku { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double NewPrice { get; set; }
    public override int GetHashCode()
    {
        return Id ^ (Name ?? "").GetHashCode() ^ (ModelNumber ?? "").GetHashCode() ^ (Sku ?? "").GetHashCode()^ (Description ?? "").GetHashCode() ^ Price.GetHashCode() ^ NewPrice.GetHashCode();
    }
}

这个想法是将所有子属性的散列组合在一起。。。你可以选择你想要的任何组合,但"xor"运算符是一个很好的选择,因为它可以防止你的哈希在你向哈希添加新属性时倾向于某些东西(就像"&"或"+"运算符一样)

编辑根据要求,对"倾向于某事"部分进行快速而肮脏的解释:

假设您选择了A&B&C&D散列值A、B、C等。你添加到哈希中的属性越多,你就越有可能拥有一个倾向于int.MaxValue的巨大哈希(对应于1111111111111111111111111111111,二进制)

与"+"相同。。。你的散列会越来越大,而不是使用完整的int值。

一个好的哈希算法就是最大限度地提高对不同值使用不同哈希的机会。要做到这一点,您可以研究在现实生活中如何使用值(可能会很痛苦,也可能会过度使用),或者最大化哈希算法为随机未知值覆盖的int值范围。

您应该重写基类Object的GetHashCode()方法。在这个overriden方法中,您可以根据Id或其他属性创建哈希代码。

你可以像这样使用它:

var hashOfp1 = p1.GetHashCode();

如果重写GetHashCode(),则还应该重写Equals(object)。代码由ReSharper 提供

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ModelNumber { get; set; }
    public string Sku { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double NewPrice { get; set; }
    protected bool Equals(Product other)
    {
        return Id == other.Id && string.Equals(Name, other.Name) && 
            string.Equals(ModelNumber, other.ModelNumber) && 
            string.Equals(Sku, other.Sku) && string.Equals(Description, other.Description) && 
            Price.Equals(other.Price) && NewPrice.Equals(other.NewPrice);
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }
        if (obj.GetType() != this.GetType())
        {
            return false;
        }
        return Equals((Product) obj);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            var hashCode = Id;
            hashCode = (hashCode*397) ^ (Name != null ? Name.GetHashCode() : 0);
            hashCode = (hashCode*397) ^ (ModelNumber != null ? ModelNumber.GetHashCode() : 0);
            hashCode = (hashCode*397) ^ (Sku != null ? Sku.GetHashCode() : 0);
            hashCode = (hashCode*397) ^ (Description != null ? Description.GetHashCode() : 0);
            hashCode = (hashCode*397) ^ Price.GetHashCode();
            hashCode = (hashCode*397) ^ NewPrice.GetHashCode();
            return hashCode;
        }
    }
}