views:

179

answers:

3

I've 2 lists of class A, A has implemented Equals(object obj) and GetHashCode() this 2 methods working correctly, code is below.

class A
{
    public string TEST 
    {
        get;
        set;
    }

    public override bool Equals(object obj)
    {
        return ((A)obj).TEST == this.TEST;
    }

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

I have 2 list of this class, firstList = { X1, X2, X3 } and secondList = { X1, X2, Y1 }. When I use firstList.Except(secondList) it always return all of elements in firstList and secondList.Except(firstList) also return every elements in secondList, as show below.

var test1 = firstList.Except(secondList).ToList(); // test1 = all elements of firstList
var test2 = secondList.Except(firstList).ToList(); // test2 = all elements of secondList

I want to know how can I solving this problem?

A: 

I don't know the type of your TEST. (The sample code does not work, since your property does not specify a type.) If TEST is a reference type (a class) you have to compare them with Equals instead of "=".

This works:

   [TestClass]
   public class UnitTest1 {
      class MyString {
         public MyString(string value) {
            _value = value;
         }
         string _value;
         public override int GetHashCode() {
            return _value.GetHashCode();
         }
         public override bool Equals(object obj) {
            MyString other = obj as MyString;
            if (other != null)
               return other._value == this._value;
            return false;
         }
      }

      [TestMethod]
      public void TestMethod1() {
         List<MyString> list1 = new List<MyString> {
            new MyString("1"),
            new MyString("2"),
         };

         List<MyString> list2 = new List<MyString> {
            new MyString("2"),
            new MyString("3"),
         };

         MyString removed = list1[1];
         var result = list1.Except(list2);
         Assert.AreEqual(1, result.Count());
         Assert.IsFalse(result.Contains(removed));
      }
   }

Greets Flo

Florian Reischl
What if TEST is string? can I use obj.TEST == this.TEST ?
In The Pink
Than it would work since string is something "very special". I changed my sample to string.
Florian Reischl
If TEST is string I need to use Equals, == always return false even it hold same value.
In The Pink
A: 

You can use the IEquatable<> interface like this

public class Test : IEquatable<Test>
{
    public string result;
    public Test(string result) { this.result = result; }
    public bool Equals(Test other)
    {
        return result.Equals(other.result);
    }
    //No need to override Equals(object obj), GetHashCode()
}

then when you check do the following

List<Test> FirstTests = ...
List<Test> SecondTests = ...

List<Test> Result = FirstTests.FindAll(delegate(Test item)
{
    return SecondTests.Contains(item);
});

For the example given above it works. I just love using anonymous methods.

jalexiou
Should the result field be public?
Peter Kelly
No. The point is that Test acts like a wrapper for a result and since Equals() has access to private members, it should not be public.
jalexiou
A: 

lookup lambda expressions and LINQ.

Adil Butt