If we have a class that contains properties/fields of other reference types, how would a proper and elegant equality check be performed?
For example, MainClass contains properties of SubClassA and SubClassB. We can assume that all of these classes override object.Equals with the same implementation, what would that be?
I came up with the following which doesn't look very nice. My logic is as follows:
We cannot use
Equalsdirectly on the reference types because they can be null, so we first check if only one of them is null, which leads to inequality.Then, if both have a value, make sure the value is equal.
We can omit the check that they are both null as it leads to equality.
class MainClass { SubClassA A {get; set;} SubClassB B {get; set;} int someint {get; set;} public override bool Equals(object obj) { MainClass other = obj as MainClass; if (other is null) return false; // First check if only one of the As is null. if (A is null ^ other.A is null) { return false; } // Then check if both have a value that the value is equal. else if (A != null && other.A != null && !A.Equals(other.A)) { return false; } // Case where As are both null is omitted as it leads to equality. // Same principle here and for any other reference types... if (B is null ^ other.B is null) { return false; } else if (B != null && other.B != null && !B.Equals(other.B)) { return false; } // Value types can go down here. return someint.Equals(other.someint); } } class SubClassA { // some properties } class SubClassB { // some properties }
Equals()override. Implement the equals operator==and!=too.SubClassA.Equals()should do anullcheck forother.SubClassA.operator ==should do anullcheck for the left side (that's possible because it'sstatic). Now you can reduce theif/else iffor each reference type property to:if (A != other.A) return false;or even better just chain multiple of them with&&.IEquatableinterface, overridingEquals(object), implementing==and!=, as well as overridingGetGashCode(). It's lots of annoying boilerplate code. But if you userecords instead ofclasses the compiler will implement it all for you. Have you considered that?