【问题标题】:How to create Hash of on instance?如何在实例上创建哈希?
【发布时间】:2014-10-27 15:52:29
【问题描述】:

我有一个产品类,

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){
        }

【问题讨论】:

标签: c# hash


【解决方案1】:

这种事情的好处是:

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 的巨大哈希(对应于 11111111111111111111111111111111,二进制)

与“+”相同...您的哈希值会越来越大,而不是使用完整的 int 值范围。

... 一个好的散列算法就是最大化不同值的不同散列的机会。为此,您可以研究如何值在现实生活中的使用(可能会很痛苦和过度杀伤),或者最大化您的哈希算法针对随机未知值覆盖的 int 值范围。

【讨论】:

  • 你能解释一下吗because it prevents your hash to tend to something as you add new properties to your hash
  • 查看我的答案,了解为什么使用 XOR 进行哈希码计算并不总是一个好的选择:stackoverflow.com/a/19139500/106159
  • @MatthewWatson 没有始终如一的好答案。但 xor 更简单,适用于大多数场景......
  • XOR 通常是可以的,我只是想指出有时它是不可以的。
  • 同一对象的哈希值会在不同的日子发生变化。来自blogs.msdn.com/b/ericlippert/archive/2011/02/28/…Suppose you have a Customer object that has a bunch of fields like Name, Address, and so on. If you make two such objects with exactly the same data in two different processes, they do not have to return the same hash code. If you make such an object on Tuesday in one process, shut it down, and run the program again on Wednesday, the hash codes can be different.
【解决方案2】:

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

你可以像这样使用它:

var hashOfp1 = p1.GetHashCode();

【讨论】:

    【解决方案3】:

    如果你覆盖 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;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-20
      • 2014-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-20
      • 2011-11-29
      • 2012-01-02
      相关资源
      最近更新 更多