-1

I have two lists of my own class, and I'm trying to get all the items in one that aren't in the other.

//List<CADataType> ConsoleDataList is a list of 1071 CADataTypes
//List<CADataType> ComDataList is a list of 2153 CADataTypes

//This list ends up containing 1144 items
List<CADataType> intersectLoose = (from console in ConsoleDataList
                                           join com in ComDataList 
                                           on console.CompareField equals com.CompareField
                                           select console).ToList();
//Therefore there are 1144 items that are in both lists

//This SHOULD result in 2153 - 1144 = 1009 items
List<CADataType> remove = ComDataList.Except(ConsoleDataList).ToList(); //<-- Problem is here
//Ends up containing 2153 items

CADataType is actually an abstract class, and all lists actually have CAPropertyData. This is the Equals class from CAPropertyData:

public override bool Equals(CADataType obj)
{
    if (!(obj is CAPropertyData))
        return false;

    CAPropertyData y = (CAPropertyData)obj;

    if (this.PropertyAddress.ToString() == y.PropertyAddress.ToString()) //Breakpoint here
        return true;
    return false;
}

I've put a breakpoint on that last if statement in the Equals, and it hits the breakpoint correctly when I step into the Except line, AND I can see that this.PropertyAddress.ToString() DOES equal y.PropertyAddress.ToString() in some cases, so it's finding some equal objects, but it doesn't seem to exclude them?

Any idea what's wrong?

EDIT: intersectLoose is there to show you that there are matching CADataTypes in both lists. CompareField is defined and using the same property as the Equals method:

public override string CompareField => PropertyAddress.ToString();
Corey Thompson
  • 398
  • 6
  • 18
  • You are using CompareField to check the common properties between them while using join. But, using except you are comparing the whole object. This wont work if two objects having same CommonField dont have all common properties too. Better use this ComDataList.Except(intersectLoose).ToList(); – Subash Kharel Jan 10 '18 at 06:45
  • This might be helpful https://stackoverflow.com/questions/2363143/whats-the-best-strategy-for-equals-and-gethashcode – Michał Turczyn Jan 10 '18 at 06:47
  • @SubashKharel in this case the `CompareField` is actually the same as the Equals - `public override string CompareField => PropertyAddress.ToString();` - But that's regardless because I use the compare field in the join for `intersectLoose` which I'm not actually using in the except – Corey Thompson Jan 10 '18 at 06:59
  • Yeah you used PropertyAddress field only for joining the object lists but compared whole the object when using except. – Subash Kharel Jan 10 '18 at 07:02
  • Using `.Except` uses the object's `Equals` method - see above in my question. My Equals method only checks the PropertyAddress field. Two CAPropertyType's are considered equal if the PropertyAddress field matches. – Corey Thompson Jan 10 '18 at 07:04

2 Answers2

0

hi this code maybe help you :

ComDataList = ComDataList.Intersect(ConsoleDataList).ToList();

or

intersectLoose = ComDataList.Intersect(ConsoleDataList).ToList();
mehdi farhadi
  • 1,415
  • 1
  • 10
  • 16
0

Have you implemented GetHashCode()? Equals() and GetHashCode() should always be implemented together.

Beware the resultant hashcode should not change once calculated (e.g. it should be based on object's ID) or you will run into problems later.

For example I often use this base class:

public abstract class DataObjectBase 
{
   public virtual int ID { get; set; }
   // true if the entity is not saved yet:
   public virtual bool IsTransient { get { return ID <= 0; } }

   // alternatively, if ID is string:
   // public virtual string ID { get; set; }
   // public virtual bool IsTransient { get { return string.IsNullOrEmpty(ID); } }

    public override bool Equals(object obj)
    {
        var other = obj as DataObjectBase;
        if (other == null)
            return false;
        else if (IsTransient ^ other.IsTransient)
            return false;
        else if (IsTransient && other.IsTransient)
            return ReferenceEquals(this, other);
        else if (this.GetType() != other.GetType())
            return false;
        else return ID == other.ID;
    }

    private int? cachedHashCode; // this is used because hashcode shouldn't change
    public override int GetHashCode()
    {
        if (cachedHashCode.HasValue) return cachedHashCode.Value;
        cachedHashCode = IsTransient ? base.GetHashCode() : ID.GetHashCode();
        return cachedHashCode.Value;
    }

    public static bool operator ==(DataObjectBase x, DataObjectBase y)
    {
        return Object.Equals(x, y);
    }

    public static bool operator !=(DataObjectBase x, DataObjectBase y)
    {
        return !(x == y);
    }
}
Arie
  • 5,251
  • 2
  • 33
  • 54
  • I've implemented the IEquatable interface which only requires the Equals (and doesn't use the GetHashCode function at all - I had implemented it earlier and it doesn't get hit in debugging) – Corey Thompson Jan 10 '18 at 06:57
  • Types that override Equals(Object) must also override GetHashCode; otherwise, hash tables might not work correctly. See: https://msdn.microsoft.com/de-de/library/bsc2ak47(v=vs.110).aspx – PinBack Jan 10 '18 at 07:50