Class does not implement Equals(object)¶
ID: cs/class-missing-equalsKind: problemSecurity severity: Severity: errorPrecision: mediumTags: - quality - reliability - correctnessQuery suites: - csharp-security-and-quality.qls
Click to see the query in the CodeQL repository
When the class of the object on whichEquals(object) is called does not define its ownEquals(object) method, anEquals(object) method defined in one of its base classes will be called instead. In the worst case, theEquals(object) method ofSystem.Object will be called, resulting in a reference equality check. This is probably not what was intended.
Classes that implement the== operator should also override theEquals(object) method, because otherwise the two forms of equality will behave differently, leading to unexpected behavior.
Recommendation¶
Implement anEquals(object) method for the highlighted class. Examine subclasses of the class highlighted to determine if they should implement their own equals method too.
Example¶
The output of this example states that “car1 does equal car2” despite the fact that one is a leaded version and one is an unleaded version. This is because theGasolineCar class is inheritingEquals(object) fromCar and that method states that twoCars are equal if their make and model are the same.
usingSystem;classBad{classCar{protectedstringmake;protectedstringmodel;publicCar(stringmake,stringmodel){this.make=make;this.model=model;}publicoverrideboolEquals(objectobj){if(objisCarc&&c.GetType()==typeof(Car))returnmake==c.make&&model==c.model;returnfalse;}}classGasolineCar:Car{protectedboolunleaded;publicGasolineCar(stringmake,stringmodel,boolunleaded):base(make,model){this.unleaded=unleaded;}}publicstaticvoidMain(string[]args){varcar1=newGasolineCar("Ford","Focus",true);varcar2=newGasolineCar("Ford","Focus",false);Console.WriteLine("car1 "+(car1.Equals(car2)?"does":"does not")+" equal car2.");}}
In the revised example,GasolineCar overridesEquals(object), and the output is “car1 does not equal car2”, as expected.
usingSystem;classGood{classCar{protectedstringmake;protectedstringmodel;publicCar(stringmake,stringmodel){this.make=make;this.model=model;}publicoverrideboolEquals(objectobj){if(objisCarc&&c.GetType()==typeof(Car))returnmake==c.make&&model==c.model;returnfalse;}}classGasolineCar:Car{protectedboolunleaded;publicGasolineCar(stringmake,stringmodel,boolunleaded):base(make,model){this.unleaded=unleaded;}publicoverrideboolEquals(objectobj){if(objisGasolineCargc&&gc.GetType()==typeof(GasolineCar))returnmake==gc.make&&model==gc.model&&unleaded==gc.unleaded;returnfalse;}}publicstaticvoidMain(string[]args){varcar1=newGasolineCar("Ford","Focus",true);varcar2=newGasolineCar("Ford","Focus",false);Console.WriteLine("car1 "+(car1.Equals(car2)?"does":"does not")+" equal car2.");}}