Overriding == operator. How to compare to null? [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I check for nulls in an ‘==’ operator overload without infinite recursion?
There is probably an easy answer to this...but it seems to be eluding me. Here is a simplified example:
public class Person
{
public string SocialSecurityNumber;
public string FirstName;
public string LastName;
}
Let's say that for this particular application, it is valid to say that if the social security numbers match, and both names match, then we are referring to the same "person".
public override bool Equals(object Obj)
{
Person other = (Person)Obj;
return (this.SocialSecurityNumber == other.SocialSecurityNumber &&
this.FirstName == other.FirstName &&
this.LastName == other.LastName);
}
To keep things consistent, we override the == and != operators, too, for the developers on the team who don't use the .Equals method.
public static bool operator !=(Person person1, Person person2)
{
return ! person1.Equals(person2);
}
public static bool operator ==(Person person1, Person person2)
{
return person1.Equals(person2);
}
Fine and dandy, right?
However, what happens when a Person object is null?
You can't write:
if (person == null)
{
//fail!
}
Since this will cause the == operator override to run, and the code will fail on the:
person.Equals()
method call, since you can't call a method on a null instance.
On the other hand, you can't explicitly check for this condition inside the == override, since it would cause an infinite recursion (and a Stack Overflow [dot com])
public static bool operator ==(Person person1, Person person2)
{
if (person1 == null)
{
//any code here never gets executed! We first die a slow painful death.
}
return person1.Equals(person2);
}
So, how do you override the == and != operators for value equality and still account for null objects?
I hope that the answer is not painfully simple. :-)

Use object.ReferenceEquals(person1, null) or the new is operator instead of the == operator:
public static bool operator ==(Person person1, Person person2)
{
if (person1 is null)
{
return person2 is null;
}
return person1.Equals(person2);
}

I've always done it this way (for the == and != operators) and I reuse this code for every object I create:
public static bool operator ==(Person lhs, Person rhs)
{
// If left hand side is null...
if (System.Object.ReferenceEquals(lhs, null))
{
// ...and right hand side is null...
if (System.Object.ReferenceEquals(rhs, null))
{
//...both are null and are Equal.
return true;
}
// ...right hand side is not null, therefore not Equal.
return false;
}
// Return true if the fields match:
return lhs.Equals(rhs);
}
"!=" then goes like this:
public static bool operator !=(Person lhs, Person rhs)
{
return !(lhs == rhs);
}
Edit
I modified the == operator function to match Microsoft's suggested implementation here.

you could alway override and put
(Object)(person1)==null
I'd imagine this would work, not sure though.

Easier than any of those approaches would be to just use
public static bool operator ==(Person person1, Person person2)
{
EqualityComparer<Person>.Default.Equals(person1, person2)
}
This has the same null equality semantics as the approaches that everyone else is proposing, but it's the framework's problem to figure out the details :)

The final (hypothetical) routine is below. It is very similar to #cdhowie's first accepted response.
public static bool operator ==(Person person1, Person person2)
{
if (Person.ReferenceEquals(person1, person2)) return true;
if (Person.ReferenceEquals(person1, null)) return false; //*
return person1.Equals(person2);
}
Thanks for the great responses!
//* - .Equals() performs the null check on person2

Cast the Person instance to object:
public static bool operator ==(Person person1, Person person2)
{
if ((object)person1 == (object)person2) return true;
if ((object)person1 == null) return false;
if ((object)person2 == null) return false;
return person1.Equals(person2);
}

Cast the Person to an Object and then perform the comparison:
object o1 = (object)person1;
object o2 = (object)person2;
if(o1==o2) //compare instances.
return true;
if (o1 == null || o2 == null) //compare to null.
return false;
//continue with Person logic.

Overloading these operators consistently is pretty hard. My answer to a related question may serve as a template.
Basically, you first need to do a reference (object.ReferenceEquals) test to see if the object is null. Then you call Equals.

cdhowie is on the money with the use of ReferenceEquals, but it's worth noting that you can still get an exception if someone passes null directly to Equals. Also, if you are going to override Equals it's almost always worth implementing IEquatable<T> so I would instead have.
public class Person : IEquatable<Person>
{
/* more stuff elided */
public bool Equals(Person other)
{
return !ReferenceEquals(other, null) &&
SocialSecurityNumber == other.SocialSecurityNumber &&
FirstName == other.FirstName &&
LastName == other.LastName;
}
public override bool Equals(object obj)
{
return Equals(obj as Person);
}
public static bool operator !=(Person person1, Person person2)
{
return !(person1 == person2);
}
public static bool operator ==(Person person1, Person person2)
{
return ReferenceEquals(person1, person2)
|| (!ReferenceEquals(person1, null) && person1.Equals(person2));
}
}
And of course, you should never override Equals and not override GetHashCode()
public override int GetHashCode()
{
//I'm going to assume that different
//people with the same SocialSecurityNumber are extremely rare,
//as optimise by hashing on that alone. If this isn't the case, change this
return SocialSecurityNumber.GetHashCode();
}
It's also worth noting that identity entails equality (that is, for any valid concept of "equality" something is always equal to itself). Since equality tests can be expensive and occur in loops, and since comparing something with itself tends to be quite common in real code (esp. if objects are passed around in several places), it can be worth adding as a shortcut:
public bool Equals(Person other)
{
return !ReferenceEquals(other, null) &&
ReferenceEquals(this, other) ||
(
SocialSecurityNumber == other.SocialSecurityNumber &&
FirstName == other.FirstName &&
LastName == other.LastName
);
}
Just how much of a benefit short-cutting on ReferenceEquals(this, other) is can vary considerably depending on the nature of the class, but whether it is worth while doing or not is something one should always consider, so I include the technique here.

Related

Overriding GetHashCode with different properties

I have this object:
public class Foo {
public string MyOwnId { get; set; }
public Guid FooGuid { get; } = Guid.NewGuid();
}
I would like Equals() to only care about those with MyOwnId, otherwise they are never equal. When a Foo has a MyOwnId I try to use it, otherwise I want to use FooGuid.
Since FooGuid probably never will be the same, I did something like this:
public bool Equals(Foo foo) {
if (foo== null) return false;
return MyOwnId.Equals(foo.MyOwnId);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Foo)obj);
}
public override int GetHashCode() {
int hash = 13;
hash = (hash*7) + (!string.IsNullOrEmpty(MyOwnId) ? MyOwnId.GetHashCode() : FooGuid.GetHashCode());
return hash;
}
Is this a proper way to do what I want? Or do I also need change my Equals method so it looks the same like my GetHashCode? For e.g:
public bool Equals(Foo foo) {
if (foo == null) return false;
if (string.IsNullOrEmpty(MyOwnId) || string.IsNullOrEmpty(foo.MyOwnId)) return false;
return MyOwnId.Equals(foo.MyOwnId);
}
Well, let's see. Your implementation of Equals and GetHashCode is erroneous.
Both Equals and GetHashCode must never throw an exception; the counter example is
Foo A = new Foo();
Foo B = new Foo() {
MyOwnId = "bla-bla-bla",
};
// Throws an exception
if (A.Equals(B)) {}
If two instances are equal via Equals these instances must have the same hash code; the counter example is
Foo A = new Foo() {
MyOwnId = "",
};
Foo B = new Foo() {
MyOwnId = "",
};
if (A.Equals(B)) {
// Hashcodes must be equal and they are not
Console.Write(String.Format("{0} != {1}", A.GetHashCode(), B.GetHashCode()));
}
Possible (simplest) implementation
// since you've declared Equals(Foo other) let others know via interface implementation
public class Foo: IEquatable<Foo> {
public string MyOwnId { get; set; }
public Guid FooGuid { get; } = Guid.NewGuid();
public bool Equals(Foo other) {
if (Object.ReferenceEquals(this, other))
return true;
else if (Object.ReferenceEquals(null, other))
return false;
else
return String.Equals(MyOwnId, other.MyOwnId);
}
public override bool Equals(object obj) {
return Equals(obj as Foo); // do not repeat youself: you've got Equals already
}
public override int GetHashCode() {
// String.GetHashCode is good enough, do not re-invent a wheel
return null == MyOwnId ? 0 : MyOwnId.GetHashCode();
}
}
Or do I also need change my Equals method so it looks the same like my GetHashCode?
You change your Equals to match how you want equality to be resolved. You've done this.
You change your GetHashCode() to key on the same information. In this case:
public override int GetHashCode()
{
return MyOwnId == null ? 0 : MyOwnId.GetHashCode();
}
Incidentally, your Equals(object) is a bit overly-complicated. I would use:
public override bool Equals(object obj)
{
return Equals(obj as Foo);
}
This passes handling the case of obj being null to the specific Equals() (which has to handle it too), deals with obj being something that isn't a Foo by passing that Equals() a null (so false anyway) and passes the handling of the case of obj being something derived from Foo to the more specific too (which again, has to handle that).
The short-cut on ReferenceEquals isn't worth doing here as there's only one field being compared, and its comparison will have the same ReferenceEquals shortcut. You don't though handle foo being a derived type in the specialised Foo. If Foo isn't sealed you should include that:
public bool Equals(Foo foo)
{
return (object)foo != null &&
foo.GetType() == GetType() &&
MyOwnId.Equals(foo.MyOwnId);
}
If Foo is sealed then that GetType() comparison should be omitted.
If the logic of the Equals() was more complicated than this then the likes of:
public bool Equals(Foo foo)
{
if ((object)foo == (object)this)
return true;
return (object)foo != null &&
foo.GetType() == GetType() &&
// Some more complicated logic here.
}
Would indeed be beneficial, but again it should be in the specific overload not the general override.
(Doing a reference-equality check is more beneficial again in == overloads, since they have to consider the possibility of both operands being null so they might as well consider that of them both being the same which implicitly includes that case).
A hash function must have the following properties:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two objects do not have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered. An implication is that small modifications to object state should result in large modifications to the resulting hash code for best hash table performance.
Hash functions should be inexpensive to compute.
The GetHashCode method should not throw exceptions.
See https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx

How should I override Equals and GetHashCode for HashSet?

Lets say I Have class:
public class Ident
{
public String Name { get; set; }
public String SName { get; set; }
}
and also one more:
class IdenNode
{
public Ident id { get; set; }
public List<IdenNode> Nodes { get; set; }
public IdenNode()
{
Nodes = new List<IdenNode>();
}
}
I want to use HashSet<IdenNode> with mind that two elements of it are same(Equal) if and only if their id.Names are Equal.
So, I'm gonna override Equals and GetHashCode like next:
public override bool Equals(object obj)
{
IdenNode otherNode = obj as IdenNode;
return otherNode != null &&
otherNode.id != null &&
id.Name == otherNode.id.Name;
}
public override int GetHashCode()
{
if (id != null)
return id.Name.GetHashCode();
else
// what should I write here?
}
Am I think right? What should I place in GetHashCode if so?
UPDATE
Could please tell me is it OK to use == and != in Equals method? Or may be ReferenceEquals or some other?
Also, should I override operators == and != ?
If id (or id.Name) is null then it's perfectly fine to return 0. Nullable<T> (like int?) returns 0 for "null" values.
Keep in mind that two objects returning the same value from GetHashCode() does NOT imply equality - it only implies that two objects might be equal. The flip, however, is that two "equal" objects must return the same hash code. Both principles seem to be fulfilled by your definition of Equals and GetHashCode
Beware of nulls! You've got a lot of them. Take care of StackOverflow: try not use == and != within Equals method. Usually, we return 0 as a hash code in case of null, e.g.:
public override bool Equals(object obj) {
// Often we should compare an instance with itself,
// so let's have a special case for it (optimization)
if (Object.ReferenceEquals(obj, this))
return true;
IdenNode other = obj as IdenNode;
// otherNode != null line in your code can cause StackOverflow:
// "!=" calls "Equals" which in turn calls "!=" etc...
if (Object.ReferenceEquals(null, other))
return false;
// Id can be null
if (Object.ReferenceEquals(id, other.id))
return true;
else if (Object.ReferenceEquals(id, null) || Object.ReferenceEquals(other.id, null))
return false;
// Let's be exact when comparing strings:
// i.e. should we use current locale or not etc
return String.Equals(id.Name, other.id.Name, StringComparison.Ordinal);
}
public override int GetHashCode() {
// It's typical to return 0 in case of null
if (Object.ReferenceEquals(null, id))
return 0;
else if (Object.ReferenceEquals(null, id.Name)) // <- Name can be null as well!
return 0;
return id.Name.GetHashCode();
}
What should I place in GetHashCode if so?
Returning zero is fine. Note that defining value equality on a name is a bad idea; I know of at least three other Eric Lipperts in the United States and they're not me. There are literally millions, possibly billions, of people who have a name collision.
Could please tell me is it OK to use "==" and "!=" in Equals method? Or may be ReferenceEquals or some other?
My advice is: when mixing reference and value equality, be very clear. If you intend reference equality, say so.
Also, should I override operators "==" and "!=" ?
Yes. It is confusing to have Equals mean one thing and == mean another.

IEquatable<T> - Best practice override for .Equals(object obj) in C#

Whenever I write a new class or struct that is likely to hold some data, that may need to be compared, I always implement IEquatable<T> as this provides the class/struct with a strongly typed .Equals(T other) method.
example:
public struct Radius : IEquatable<Radius>
{
public Int32 TopLeft { get; set; }
public Int32 TopRight { get; set; }
public Int32 BottomLeft { get; set; }
public Int32 BottomRight { get; set; }
public bool Equals(Radius other)
{
return this.TopLeft == other.TopLeft
&& this.TopRight == other.TopRight
&& this.BottomLeft == other.BottomLeft
&& this.BottomRight == other.BottomRight;
}
}
As well as providing an implementation for .Equals(Radius other), I should really override the default implementation too (.Equals(object obj))
I have two options here, and my question is, which of these implementations is better?
Option 1 is to use casting:
public override bool Equals(object obj)
{
return this.Equals((Radius)obj);
}
Option 2 is to use the "as" keyword:
public override bool Equals(object obj)
{
return this.Equals(obj as Radius);
}
My reason for asking this is, using casting will throw an exception if obj cannot be cast to Radius, whereas as will resolve to null if it cannot be cast, therefore it just checks this against null, without throwing an exception; So is it better to throw an exception, or to just return false?
EDIT: As it has been pointed out by quite a few fellow SO'ers, structs cannot be null, therefore the second option does not apply for a struct. Therefore another question springs to mind: Should the overridden implementation of .Equals(object obj) be identical for structs and classes?
The Equals() method must never throw an exception.
An object of a different type is merely unequal.
Quoting the documentation:
Implementations of Equals must not throw exceptions; they should always return a value. For example, if obj is null, the Equals method should return false instead of throwing an ArgumentNullException.
As #SLaks already mentioned Equals() should never throw.
In this special case i think a usage of the is operator combined with a cast should help you out:
public override bool Equals(object obj)
{
if(obj is Radius)
return Equals((Radius)obj);
return false;
}
In cases where you have a class you should simply use the as operator:
public override bool Equals(object obj)
{
return Equals(obj as MyObj);
}
public bool Equals(MyObj obj)
{
if(ReferenceEquals(obj, null))
return false;
// ToDo: further checks for equality.
}
My personal opinion would be to use the second option, or even check before hand if the object is a "Radius" and then return false so that the intent is more clear

c# List<T>.Contains() Method Returns False

In the code block below I would expect dictCars to contain:
{ Chevy:Camaro, Dodge:Charger }
But, dictCars comes back empty. Because this line returns false each time it's called:
if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))
Code block:
public class Car
{
public long CarID { get; set; }
public string CarName { get; set; }
public Car(long CarID, string CarName)
{
this.CarID = CarID;
this.CarName = CarName;
}
}
List<Car> myCars = new List<Car>();
myCars.Add(new Car(0,"Pinto"));
myCars.Add(new Car(2,"Camaro"));
myCars.Add(new Car(3,"Charger"));
Dictionary<string, string> dictCars = new Dictionary<string, string>();
string strCars = "Ford:1:Mustang,Chevy:2:Camaro,Dodge:3:Charger";
String[] arrCars = strCars.Split(',');
foreach (string strCar in arrCars)
{
if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))
{
if (!dictCars.ContainsKey(strCar.Split(':')[0]))
{
dictCars.Add(strCar.Split(':')[0], strCar.Split(':')[2]);
}
}
}
return dictCars;
Question: What am I doing wrong with my List.Contains implementation?
Thanks in advance!
You need to tell Contains what makes two Cars equal. By default it will use ReferenceEquals which will only call two objects equal if they are the same instance.
Either override Equals and GetHashCode in your Car class or define an IEqualityComparer<Car> class and pass that to Contains.
If two Cars that have the same CarID are "equal" then the implementation is pretty straightforward:
public override bool Equals(object o)
{
if(o.GetType() != typeof(Car))
return false;
return (this.CarID == ((Car)o).CarID);
}
public override int GetHashCode()
{
return CarID.GetHashCode();
}
Your Car class is a reference type. By default reference types are compared to each other by reference, meaning they are considered the same if they reference the same instance in memory. In your case you want them to be considered equal if they contain the same values.
To change the equality behavior, you need to override Equals and GetHashCode.
If two cars are equal only when ID and Name are equal, the following is one possible implementation of the equality members:
protected bool Equals(Car other)
{
return CarID == other.CarID && string.Equals(CarName, other.CarName);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
var other = obj as Car;
return other != null && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (CarID.GetHashCode() * 397) ^
(CarName != null ? CarName.GetHashCode() : 0);
}
}
This implementation has been created automatically by ReSharper.
It takes into account null values and the possibility of sub-classes of Car. Additionally, it provides a useful implementation of GetHashCode.
You can add this code, by implementing IEquatable
public class Car: IEquatable<Car>
{
......
public bool Equals( Car other )
{
return this.CarID == other.CarID && this.CarName == other.CarName;
}
}
Link : http://msdn.microsoft.com/fr-fr/library/vstudio/ms131187.aspx
You are assuming that two Car instances that have the same CarID and CarName are equal.
This is incorrect. By default, each new Car(...) is different from each other car, since they are references to different objects.
There are a few ways to "fix" that:
Use a struct instead of a class for your Car.
Structs inherit ValueType's default implementation of Equals, which compares all fields and properties to determine equality.
Note that in this case, it is recommended that you make your Car struct immutable to avoid common problems with mutable structs.
Override Equals and GetHashCode.
That way, List.Contains will know that you intend Cars with the same ID and Name to be equal.
Use another method instead of List.Contains.
For example, Enumerable.Any allows you to specify a predicate that can be matched:
bool exists = myCars.Any(car => car.ID == Convert.ToInt64(strCar.Split(':')[1])
&& car.Name = strCar.Split(':')[2]);
You need to implement Equals. Most probably as:
public override bool Equals(object obj)
{
Car car = obj as Car;
if(car == null) return false;
return car.CarID == this.CarID && car.CarName == this.CarName;
}
Your car class needs to implement interface IEquatable and define an Equals method, otherwise the contains method is comparing the underlying references.
You need to implement the IEqualityComparer
More information on how to do it can be found here;
http://msdn.microsoft.com/en-us/library/bb339118.aspx
// Custom comparer for the class
class CarComparer : IEqualityComparer<Car>
{
// Products are equal if their names and product numbers are equal.
public bool Equals(Car x, Car y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the properties are equal.
return x.CarID == y.CarID && x.CarName == y.CarName;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Car car)
{
//Check whether the object is null
if (Object.ReferenceEquals(car, null)) return 0;
//Get hash code for the Name field if it is not null.
string hashCarName = car.CarName == null ? 0 : car.CarName.GetHashCode();
//Get hash code for the ID field.
int hashCarID = car.CarID.GetHashCode();
//Calculate the hash code for the product.
return hashCarName ^ hashCarID;
}
Check for equality;
CarComparer carComp = new CarComparer();
bool blnIsEqual = CarList1.Contains(CarList2, carComp);
A collection can never "contain" a newly newed object which uses the default Object.Equals comparison. (The default comparison is ReferenceEquals, which simply compares instances. This will never be true comparing an existing Car with a new Car())
To use Contains in this way, you will need to either:
Override Car.Equals (and Car.GetHashCode) to specify what it means to be equivalent, or
Implement an IEqualityComparer<Car> to compare the instances and specify that in your call to Contains.
Note the side effect that in the first option, other uses of Car.Equals(Car) will also use this comparison.
Otherwise, you can use Any and specify the comparison yourself (but IMHO this smells a little funny - a Car should know how to compare itself):
if(myCars.Any(c=> c.CarID == Convert.ToInt64(strCar.Split(':')[1]) && c.CarName == strCar.Split(':')[2]))
myCars.Contains(newCar)
myCars.Where(c => c.CarID == newCar.CarID && c.CarName==newCar.CarName).Count() > 0

Inheriting the equality comparer

I have a Customer class.
public class Customer
{
private string _id;
private string _name;
// some more properties follow
I am inheriting the EqualityComparer form MyEqualityComparer(of Customer).
This I am intending to use in LINQ queries.
MyEqualityComparer is intended for partial check between two objects.
If the customer.id and customer.name matches I treat the objects the equal.
public class MyComparer : System.Collections.Generic.EqualityComparer<Customer>
{
public override bool Equals(Customer x, Customer y)
{
if (x.Id == y.Id && x.Name == y.Name)
return true;
else
return false;
}
public override int GetHashCode(Customer obj)
{
return string.Concat(obj.Id,obj.Name).GetHashCode();
}
}
I referred to generating hashcode.
I am little unsure about concatenating strings and using that as a hashcode.
Is this safe and sound what I am trying to do ?
See this question on hashcodes for a pretty simple way to return one hashcode based on multiple fields.
Having said that, I wouldn't derive from EqualityComparer<T> myself - I'd just implement IEqualityComparer<T> directly. I'm not sure what value EqualityComparer<T> is really giving you here, other than also implementing the non-generic IEqualityComparer.
A couple more things:
You should handle nullity in Equals
Your present Equals code can be simplified to:
return x.Id == y.Id && x.Name == y.Name;
A fuller implementation of Equals might be:
public override bool Equals(Customer x, Customer y)
{
if (object.ReferenceEquals(x, y))
{
return true;
}
if (x == null || y == null)
{
return false;
}
return x.Id == y.Id && x.Name == y.Name;
}
You should see it from the perspective of possible "collisions", e.g. when two different objects get the same hash code. This could be the case with such pairs as "1,2any" and "12, any", the values in the pairs being "id" and "name". If this is not possible with your data, you're good to go. Otherwise you can change it to something like:
return obj.Id.GetHashCode() ^ obj.Name.GetHashCode();
Resharper (fantastic refactoring plugin from JetBrains) thinks it should be:
public override int GetHashCode(Customer obj)
{
unchecked
{
return ((obj.Id != null ? obj.Id.GetHashCode() : 0) * 397)
^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
}
}
I have to admit I almost always just let Resharper generate the equality and hash code implementations for me. I've tested their implementation a great deal and found it to be as good if not better than anything I'd write by hand. So I'll usually take the implementation I don't have to type.

Categories

Resources