Your code works fine for me - tracking through ReferenceSource, the default comparison is ultimately uses is an ObjectEqualityComparer which calls Equals()
, so your idea is correct.
So it comes down to how you implement Equals
and GetHashCode
. You should override both if you override one, as MSDN states:
CAUTION: If you override the GetHashCode method, you should also override Equals, and vice versa. If your overridden Equals method returns true when two objects are tested for equality, your overridden GetHashCode method must return the same value for the two objects.
Note your ID
class will also need to handle both these methods correctly as it should be used by Plan
to check for equality and getting the hashcode.
This program worked for me and only prints the second entry with ID=2
(note that I made SomeOtherProperty
and int
for simplicity but this doesn't affect the approach or code):
class Program
{
public class Plan
{
public int ID { get; set; }
public Plan Parent { get; set; }
public int SomeOtherProperty { get; set; }
// added to show we don't care about this
public string IgnoreMe { get; set; }
public Plan(int id, int other, Plan parent, string ignore)
{
this.ID = id;
this.SomeOtherProperty = other;
this.Parent = parent;
this.IgnoreMe = ignore;
}
public override bool Equals(object obj)
{
Plan other = (Plan)obj;
// just check the relevant properties
return this.ID == other.ID
&& this.SomeOtherProperty == other.SomeOtherProperty
&& this.Parent == other.Parent;
// .. or alternatively
//return (new { ID, SomeOtherProperty, Parent })
// .Equals(new { other.ID, other.SomeOtherProperty, other.Parent });
}
// nicked from http://stackoverflow.com/a/4630550/1901857
public override int GetHashCode()
{
return new { ID, SomeOtherProperty, Parent }.GetHashCode();
}
// just to help debug
public override string ToString()
{
return string.Format("[ID: {0}, Other:{1}, Parent:{2}]", ID, SomeOtherProperty, Parent);
}
}
static void Main(string[] args)
{
var parentPlans = new Plan[] {
new Plan(101, 2, null, "parent1"),
new Plan(102, 3, null, "parent2"),
new Plan(103, 4, null, "parent3"),
new Plan(104, 5, null, "parent4")
};
List<Plan> oldPlans = new List<Plan>(new Plan[] {
new Plan(1, 2, parentPlans[0], "old1"),
new Plan(2, 3, parentPlans[1], "old2"),
new Plan(3, 4, parentPlans[2], "old3"),
new Plan(4, 5, parentPlans[3], "old4")
});
List<Plan> newPlans = new List<Plan>(new Plan[] {
new Plan(11, 2, parentPlans[0], "new1"), // different ID
new Plan(2, 3, parentPlans[1], "new2"), // same
new Plan(3, 14, parentPlans[2], "new3"), // different other ID
new Plan(4, 5, parentPlans[2], "new4") // different parent
});
foreach (var e in
oldPlans.Join(newPlans, o => o, n => n, (o, n) => new { Old = o, New = n }))
{
Console.WriteLine(e.Old + " / " + e.New);
};
}
}
If you think your implementations of Equals
and GetHashCode
should have worked, then please post them in the question, maybe they are not quite right.