Search code examples
c#hashcodeintersectexcept

Is my syncfunctions hashCode usage approach correct?


Please read my previous question, because my fear of getting collision when using hashCode for strings ! Previous question

I having a database table with items in a repo, and a "incoming" function with items from a model that should sync - to the database table.

Im using intersect and except to make this possible.

The class i use for my sunc purpose:

        private class syncItemModel
    {

        public override int GetHashCode()
        {
            return this.ItemLookupCode.GetHashCode();
        }

        public override bool Equals(object other)
        {
            if (other is syncItemModel)
                return ((syncItemModel)other).ItemLookupCode == this.ItemLookupCode;
            return false;
        }

        public string Description { get; set; }
        public string ItemLookupCode { get; set; }

        public int ItemID { get; set; }

    }

Then i use this in my method: 1) Convert datatable items to syncmodel:

                    var DbItemsInCampaignDiscount_SyncModel =
                     DbItemsInCampaignDiscount(dbcampaignDiscount, datacontext)
                                     .Select(i => new syncItemModel { Description = i.Description, 
                                      ItemLookupCode = i.ItemLookupCode, 
                                      ItemID = i.ID}).ToList();

2) Convert my incoming item model to syncmodel:

                   var ItemsInCampaignDiscountModel_SyncModel = modelItems
                                        .Select(i => new syncItemModel { Description = 
                         i.Description, ItemLookupCode = i.ItemLookUpCode, ItemID =0 }).ToList();

3) Make an intersect:

                   var CommonItemInDbAndModel = 
     ItemsInCampaignDiscountModel_SyncModel.Intersect(DbItemsInCampaignDiscount_SyncModel).ToList();

4) Take out items to be deleted in database (that not exist in incoming model items)

                   var SyncModel_OnlyInDb = 
              DbItemsInCampaignDiscount_SyncModel.Except(CommonItemInDbAndModel).ToList();

5) Take out items to be added to database, items that exist in incoming model but not in db:

                    var SyncModel_OnlyInModel = 
         ItemsInCampaignDiscountModel_SyncModel.Except(CommonItemInDbAndModel).ToList();

My question is then - can it be a collision? Can two differnt ItemLookupCode in my example be treated as the same ItemLookupCode? Because intersect and except using HashCode ! Or vill the Equal function "double check" it -so this approach is safe to use? If its a possible chance of collision how big is that chance?


Solution

  • Yes, there could be always a hash-collision, that's why identity should be confirmed by calling Equals(). GetHashCode() and Equals() must be implemented correctly.

    Except() in LINQ to Objects internally uses HashSet, in case of hash-collision it will call Equals to guarantee identity. As you are using a single property, you are good to proxy calls to its hashcode and equals methods.

    Please find some comments below about your implementation:

    comparison with ==

    This is fine to compare strings with ==, but if type is changed to non-primitive, you'll get issues because object reference instead of content will be compared. Proxy call to Equals() instead of ==.

    mutability of the object

    That is very error prone to bound gethashcode/Equals logic to mutable state. I'd strongly recommend to encapsulate your state so that once you create your object it could not be changed, make set private for a sake of safety.