1

I have a Product class,

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; }
}

I am saving this class in my database table. But I also need to save the hash of the each object in my database table for change tracking. What I am looking is that,

        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){
        }
Imran Qadir Baksh - Baloch
  • 32,612
  • 68
  • 179
  • 322
  • 2
    See this answer for getting hashcodes based on object properties: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode – Smudge202 Sep 03 '14 at 08:14

3 Answers3

2

A good for this kind of things is :

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();
    }
}

The idea is to combine hashes of all sub properties... you could choose any combination you wish, but "xor" operator is quite a good choice because it prevents your hash to tend to something as you add new properties to your hash (like a "&" or "+" operator would)

edit Quick and dirty explanation for the "tend to something" part, as requested:

Let's assume you chose A & B & C & D ... to hash values A, B, C etc. The most properties you add to your hash, the more chance you will have to have a huge hash that tends to int.MaxValue (which corresponds to 11111111111111111111111111111111, binary)

Same thing with "+"... your hashes will get bigger and bigger, not using the full spectrum of int values.

... A good hash algorithm is just about maximizing the chances to have a different hash for different values. To do that, you can either study how values are used in real life (can be painful and overkill), or maximize the spectrum of int values that your hash algorithm covers for random unknown values.

Olivier
  • 5,578
  • 2
  • 31
  • 46
  • can you explain a bit `because it prevents your hash to tend to something as you add new properties to your hash` – Imran Qadir Baksh - Baloch Sep 03 '14 at 08:26
  • See my answer here for why using XOR for hash code computation isn't always a good choice: http://stackoverflow.com/a/19139500/106159 – Matthew Watson Sep 03 '14 at 08:26
  • @MatthewWatson there is no answer that is consistently good. But xor is the simpler and is fine for most scenarios... – Olivier Sep 03 '14 at 08:28
  • XOR is often ok, I just wanted to point out that sometimes it is not ok. – Matthew Watson Sep 03 '14 at 08:35
  • Will the hash of same object can change on different days. From http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx, `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.` – Imran Qadir Baksh - Baloch Sep 03 '14 at 11:02
  • Can you recommend this, http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode – Imran Qadir Baksh - Baloch Sep 03 '14 at 11:07
2

You should override the GetHashCode() method of the base class Object. In this overriden method you can create a hash code based on the Id or other properties.

You can use it then like:

var hashOfp1 = p1.GetHashCode();
Nagelfar
  • 803
  • 2
  • 8
  • 21
2

If you override GetHashCode() you should also override Equals(object). Code courtesy of 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;
        }
    }
}
Rytis I
  • 1,105
  • 8
  • 19