1

I have implemented a comparison class for my custom class, so that I can use Intersect on two lists (StudentList1 and StudentList2). However, when I run the following code, I don't get any results.

Student:

class CompareStudent : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (x.Age == y.Age && x.StudentName.ToLower() == y.StudentName.ToLower())
            return true;
        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.GetHashCode();
    }
}

class Student
{
    public int StudentId{set;get;}
    public string StudentName{set;get;}
    public int Age{get;set;}
    public int StandardId { get; set; }
}

Main:

IList<Student> StudentList1 = new List<Student>{
                new Student{StudentId=1,StudentName="faisal",Age=29,StandardId=1},
                new Student{StudentId=2,StudentName="qais",Age=19,StandardId=2},
                new Student{StudentId=3,StudentName="ali",Age=19}
            };
IList<Student> StudentList2 = new List<Student>{
                new Student{StudentId=1,StudentName="faisal",Age=29,StandardId=1},
                new Student{StudentId=2,StudentName="qais",Age=19,StandardId=2},

            };

var NewStdList = StudentList1.Intersect(StudentList2, new CompareStudent());

Console.ReadLine();
Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147
Faisal Naseer
  • 4,110
  • 1
  • 37
  • 55

2 Answers2

3

The problem is within your GetHashCode() method, change it to:

public int GetHashCode(Student obj)
{
    return obj.StudentId ^ obj.Age ^ obj.StandardId ^ obj.StudentName.Length;
}

In your current code, Equals is not called as the current GetHashCode() returns two different integers, so no point in calling Equals.

If GetHashCode of the first object is different than the second, the objects are not equal, if the result is the same, Equals is being called.

The GetHashCode I've written above is not ultimate, see What is the best algorithm for an overridden System.Object.GetHashCode? for more details on how to implement GetHashCode.

GetHashCode() is not (and cannot be) collision free, which is why the Equals method is required in the first place.

Community
  • 1
  • 1
Ofiris
  • 6,047
  • 6
  • 35
  • 58
  • 3
    I like (and use) this implementation from the thread you linked: http://stackoverflow.com/a/18613926/3191599 – Nate Barbettini Jan 31 '15 at 19:17
  • Hi, Ofiris. First of all thanks for the solution. I have also tried Contains with particular ComparStudent class and returning the GetHashCode() of obj but it runs fine with particular statement. Do i need to use the particular solution for Conatns aswell or it behaves different in current scenerio. Student std = new Student { StudentName="faisal",Age=29}; bool result3 = StudentList.Contains(std,new CompareStudent()); – Faisal Naseer Feb 01 '15 at 05:35
  • Yes, same answer is relevant for `Contains`: `StudentList2.Contains(new Student{StudentId=2,StudentName="qais",Age=19,StandardId=2}, new CompareStudent()) //true` – Ofiris Feb 01 '15 at 06:29
  • Concerning the use of XOR (`^`) to compute a hash code from a composite value, see Eric Lippert's blog article [Guidelines and rules for GetHashCode](http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx): _"'xor' can create or exacerbate distribution problems when there is redundancy in data structures."_ – stakx - no longer contributing Feb 01 '15 at 06:37
  • @Ofiris actually im trying to ask Why the previous CompareStudent class pointed in question works well with compare? – Faisal Naseer Feb 01 '15 at 06:47
  • If this answer solves your original question, mark it as answer and if you have any additional questions, you can post them in separately. – Ofiris Feb 03 '15 at 19:12
1

You are calling GetHashCode() on the base object, which will return a different value for the different references. I would implement it like this:

    public override int GetHashCode(Student obj)
    {
        unchecked
        {
            return obj.StudentName.GetHashCode() + obj.Age.GetHashCode();
        }
    }
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • +1. But given that there is a `StudentId` property, which supposedly uniquely identifies a student, why not use just that (instead of `StudentName` and `Age`) to compute the hash? `return obj.StudentId.GetHashCode();` (without `unchecked`) should suffice. – stakx - no longer contributing Feb 01 '15 at 06:39
  • The original question did not use the student id in the equals implementation, so I assumed that they did not intend to use it for equality. – John Koerner Feb 01 '15 at 13:42