126

I have never really done this before so i was hoping that someone could show me the correct what of implementing a override of Except() and GetHashCode() for my class.

I'm trying to modify the class so that i can use the LINQ Except() method.

public class RecommendationDTO{public Guid RecommendationId { get; set; }
public Guid ProfileId { get; set; }
public Guid ReferenceId { get; set; }
public int TypeId { get; set; }
public IList<TagDTO> Tags { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public bool IsActive { get; set; }
public object ReferencedObject { get; set; }
public bool IsSystemRecommendation { get; set; }
public int VisibilityScore { get; set; }

public RecommendationDTO()
{
}

public RecommendationDTO(Guid recommendationid,
                            Guid profileid,
                            Guid referenceid,
                            int typeid,
                            IList<TagDTO> tags,
                            DateTime createdon,
                            DateTime modifiedon, 
                            bool isactive,
                            object referencedobject)
{
    RecommendationId = recommendationid;
    ProfileId = profileid;
    ReferenceId = referenceid;
    TypeId = typeid;
    Tags = tags;
    CreatedOn = createdon;
    ModifiedOn = modifiedon;
    ReferencedObject = referencedobject;
    IsActive = isactive;
}

public override bool Equals(System.Object obj)
{
    // If parameter is null return false.
    if (obj == null)
    {
        return false;
    }

    // If parameter cannot be cast to Point return false.
    RecommendationDTO p = obj as RecommendationDTO;
    if ((System.Object)p == null)
    {
        return false;
    }

    // Return true if the fields match:
    return (ReferenceId == p.ReferenceId);// && (y == p.y);
}

public bool Equals(RecommendationDTO p)
{
    // If parameter is null return false:
    if ((object)p == null)
    {
        return false;
    }

    // Return true if the fields match:
    return (ReferenceId == p.ReferenceId);// && (y == p.y);
}

//public override int GetHashCode()
//{
//    return ReferenceId;// ^ y;
//}}

I have taken a look at http://msdn.microsoft.com/en-us/library/ms173147.aspx but i was hoping someone could show me within my own example.

Any help would be appreciated.

Thank you

Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
Nugs
  • 5,503
  • 7
  • 36
  • 57
  • On the page you linked to: "It is not a good idea to override operator == in non-immutable types." There are other and better ways to make Except() work. – H H Feb 16 '12 at 19:36
  • @Henk Holterman overriding equality operator == is not recommended; overriding Equals isn't not recommended. – Souhaieb Besbes Jan 11 '16 at 11:02
  • @SouhaiebBesbes - it is (very strongly) recommended to keep `==` and `Equals()` in sync. – H H Jan 11 '16 at 11:27
  • 3
    VS 2017 will generate these https://learn.microsoft.com/en-us/visualstudio/ide/reference/generate-equals-gethashcode-methods – Matt Morgan Aug 22 '18 at 15:44

3 Answers3

154

You can override Equals() and GetHashCode() on your class like this:

public override bool Equals(object obj)
{
    var item = obj as RecommendationDTO;

    if (item == null)
    {
        return false;
    }

    return this.RecommendationId.Equals(item.RecommendationId);
}

public override int GetHashCode()
{
    return this.RecommendationId.GetHashCode();
}
Craig
  • 6,869
  • 3
  • 32
  • 52
  • Do i not have to implement IEquatable<>?: public class RecommendationDTO : IEquatable... When i do i get a error: DataTransferObjects.RecommendationDTO does not implement interface member System.IEquatable.Equals(DataTransferObjects.RecommendationDTO) – Nugs Feb 16 '12 at 19:41
  • 11
    This is a very basic solution that doesn't address best practices , especially with the hash code generation and overriding the related == and != operators. – LostNomad311 Oct 17 '17 at 17:12
  • 2
    as check is not enough in the general case because obj could be an instance of a class derived from the current one – ovolko Nov 10 '17 at 22:06
  • What about those that derive from `System.ValueType`, such as `struct`s instead of `class`es which derive from `System.Object`? – code_dredd Mar 28 '18 at 08:21
  • @code_dredd For structs see [this answer](https://stackoverflow.com/a/2542712/1057791). – BornToCode Dec 13 '18 at 10:44
  • 1
    pattern matching also will account for null `if (!(obj is RecommendationDTOitem)) { return false }` – TwoFingerRightClick Mar 02 '22 at 18:07
17
public override bool Equals(System.Object obj)
{
    // Check if the object is a RecommendationDTO.
    // The initial null check is unnecessary as the cast will result in null
    // if obj is null to start with.
    var recommendationDTO = obj as RecommendationDTO;

    if (recommendationDTO == null)
    {
        // If it is null then it is not equal to this instance.
        return false;
    }

    // Instances are considered equal if the ReferenceId matches.
    return this.ReferenceId == recommendationDTO.ReferenceId;
}

public override int GetHashCode()
{
    // Returning the hashcode of the Guid used for the reference id will be 
    // sufficient and would only cause a problem if RecommendationDTO objects
    // were stored in a non-generic hash set along side other guid instances
    // which is very unlikely!
    return this.ReferenceId.GetHashCode();
}
Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
15

Be careful when using a primary key as your test for equality in overriding Equals() because it only works AFTER the object has been persisted. Prior to that your objects don't have primary keys yet and the IDs of the ones in memory are all zero.

I use base.Equals() if either of the object IDs is zero but there probably is a more robust way.

Eric Nelson
  • 763
  • 1
  • 8
  • 17