I am a little confused on content equality in reference types specifically. I am not overriding Equality in either case - so why is the behavior different.
See 2 simple code examples:
Example 1: Returns True
class Program
{
static void Main(string[] args)
{
object o1 = "ABC";
object o2 = "ABC";
Console.WriteLine("object1 and object2: {0}", o1.Equals(o2));
}
}
Example 2: Both statements return False
class Program
{
static void Main(string[] args)
{
Person person1 = new Person("John");
Person person2 = new Person("John");
Console.WriteLine("person1 and person2: {0}", person1.Equals(person2));
Console.WriteLine("person1 and person2: {0}", ((object)person1).Equals((object)person2));
Console.ReadLine();
}
}
public class Person
{
private string personName;
public Person(string name)
{
this.personName = name;
}
}
There are two effects at work here:
String interning means that actually even if you perform a reference equality check, you'll still see True
. You can fix that like this:
object o1 = new StringBuilder("ABC").ToString();
object o2 = new StringBuilder("ABC").ToString();
System.String
overrides the Equals
method to compare the contents of the strings:
This method performs an ordinal (case-sensitive and culture-insensitive) comparison.
You can see the difference here:
object o1 = new StringBuilder("ABC").ToString();
object o2 = new StringBuilder("ABC").ToString();
Console.WriteLine(o1.Equals(o2)); // Prints True due to overriding
Console.WriteLine(ReferenceEquals(o1, o2)); // Prints False
Your class doesn't override Equals
, so you're getting the default implementation in Object
, which is to compare references:
If the current instance is a reference type, the Equals(Object) method tests for reference equality, and a call to the Equals(Object) method is equivalent to a call to the ReferenceEquals method.
You could fix that reasonably easily by overriding Equals
:
// It's easier to implement equality correctly on sealed classes
public sealed class Person
{
private readonly string personName;
public Person(string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
this.personName = name;
}
public override bool Equals(object other)
{
Person person = other as Person;
return person != null && person.personName.Equals(personName);
}
// Must override GetHashCode at the same time...
public override int GetHashCode()
{
// Just delegate to the name here - it's the only thing we're
// using in the equality check
return personName.GetHashCode();
}
}
Note that in the Equals
implementation we could have used:
return person != null && person.personName == personName;
... because string
also overloads the ==
operator. But that's a different matter :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With