views:

270

answers:

5

How does the == operator really function in C#? If it used to compare objects of class A, will it try to match all of A's properties, or will it look for pointers to the same memory location (or maybe something else)?

Let's create a hypothetical example. I'm writing an application that utilizes the Twitter API, and it has a Tweet class, which has all the properties of a single tweet: text, sender, date&time, source, etc. If I want to compare objects of class Tweet for equivalence, can I just use:

Tweet a, b;
if (a == b)
{
//do something...
}

Will that check for equivalence of all the properties of the Tweet class between a and b?

If not, would the correct approach be to overload the == operator to explicitly check for equivalence of all the fields?

UPDATE: From the first two answers, am I right in assuming:

  • If the == operator or Equals method is not overloaded for a class, the == operator for the object class is used.
  • The == operator for the object class checks for equality in memory location.
  • I have to overload the == operator or the Equals method to accomplish this task.
  • In the overload, I have to check for equivalence in properties manually, so there is no way to do it semi-automatically, say, in a loop, right?

UPDATE #2: Yuriy made a comment that it is possible to do check for equivalence in properties in the == operator with reflection. How can this be done? Could you give me some sample code? Thanks!

+2  A: 

The proper approach is the overload the equals method of the Tweet class in addition to the == operator, as described here.

Kaleb Brasee
So I would then have to manually check for equivalence of each of the properties? Is there a faster way to do this, say in a loop somehow?
Maxim Zaslavsky
@Maxim: You could use reflection to compare all the fields. How many fields do you have? Watch out for SRP.
Yuriy Faktorovich
You can use reflection to run the equals function on all your inner properties.
Am
Not that I'm aware of in C#. Java IDEs allow you to completely generate the equals method code for a class automatically, maybe Visual Studio has something like that?
Kaleb Brasee
@Yuriy @Am can you give me some sample code in an answer? Thanks!
Maxim Zaslavsky
+1  A: 

Will that check for equivalence of all the properties of the Tweet class between a and b?

No

If not, would the correct approach be to overload the == operator to explicitly check for equivalence of all the fields?

You can either overload the == operator, or overload the Equals function.

Edit

@Yuriy gave a good example for compating all the non public variables. Since i also wrote an example, here it is (mine compares properties)

class TwitterItem
{
    private string myValue = "default value";
    public string Value1
    {
        get { return myValue; }
        set { myValue = value; }
    }
    public string Value2
    {
        get { return myValue; }
        set { myValue = value; }
    }
    public string Value3
    {
        get { return myValue; }
        set { myValue = value; }
    }

    public override bool Equals(object obj)
    {
        if (base.Equals(obj)) return true;

        Type type = typeof(TwitterItem);
        PropertyInfo[] properties = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            if (false == property.GetValue(this, null).Equals(property.GetValue(obj, null)))
                return false;
        }

        return true;
    }
}
Am
Thanks so much, this really helps!
Maxim Zaslavsky
+2  A: 

MSDN has a good example of how to do it:

   public override bool Equals(object o) 
   {
      try 
      {
         return (bool) (this == (DBBool) o);
      }
      catch 
      {
         return false;
      }
   }

Then you overload the == and !=:

// Equality operator. Returns dbNull if either operand is dbNull, 
   // otherwise returns dbTrue or dbFalse:
   public static DBBool operator ==(DBBool x, DBBool y) 
   {
      if (x.value == 0 || y.value == 0) return dbNull;
      return x.value == y.value? dbTrue: dbFalse;
   }

   // Inequality operator. Returns dbNull if either operand is
   // dbNull, otherwise returns dbTrue or dbFalse:
   public static DBBool operator !=(DBBool x, DBBool y) 
   {
      if (x.value == 0 || y.value == 0) return dbNull;
      return x.value != y.value? dbTrue: dbFalse;
   }

And don't forget to overload the GetHash method.

Edit:

I wrote the following quick sample for using reflection in a compare. This would have to be much more comprehensive, I might try doing a blog on it if people want me to:

public class TestEquals
{
    private int _x;
    public TestEquals(int x)
    {
        this._x = x;
    }

    public override bool Equals(object obj)
    {
        TestEquals te = (TestEquals)obj;
        if (te == null) return false;

        foreach (var field in typeof(TestEquals)
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
        {
            if (!field.GetValue(this).Equals(field.GetValue(te)))
                return false;
        }
        return true;
    }
}
Yuriy Faktorovich
+1 for the reflection solution (thats the second time you post a minute before me :)
Am
And how would you implement GetHashCode() using a reflection-based approach like this?
John Rayner
@John: Why not using reflection in combination with Jon Skeet's answer: http://stackoverflow.com/questions/263400#263416
Yuriy Faktorovich
Why *use* reflection?
pst
@pst: Here is an example, lets say you have a class generated from Sql Server for LinqToSql. It doesn't have an Equals, but you're not sure what all the fields are going to be, and don't want to add new ones each time its generated. So you override the Equals in a partial class which reflects over the fields, maybe excludes the id, and you're done.
Yuriy Faktorovich
Reflection should be used sparingly, and only when you don't know about the types involved. Don't use it as a general solution for implementing Equals. Don't be lazy! :)
GraemeF
@GraemeF: that was the exact example I just gave. For my current project I generate a class based on an xml schema. If I ever needed to compare it, this exactly how I would do it. Why should reflection be used sparingly anyways? It is used all over the place.
Yuriy Faktorovich
+3  A: 

For reference types, the default implementations of both the == operator and the Equals() method will simply check that both objects have the same reference, and are therefore the same instance.

If you want to check the contents of two different objects are equal then you must write the code to do it yourself, one way or another. It would be possible to do with reflection (the MbUnit test framework does something along these lines) but with a heavy performance penalty and a good chance that it wouldn't do quite what you expected anyway, and you should implement == or Equals and GetHashCode by hand.

GraemeF
+1 for noting the performance and complexity consequences with the reflection-based solution.
Erik Forbes
+1  A: 

You can compare the properties using reflection:

var a = new Entity() { Name = "test", ID = "1" };
var b = new Entity() { Name = "test", ID = "1" };
var c = new Entity() { Name = "test", ID = "2" };
System.Diagnostics.Debug.WriteLine(a.Equals(b));//Returns true
System.Diagnostics.Debug.WriteLine(a.Equals(c));//Returns false


public class Entity
{
    public string Name { get; set; }
    public string ID { get; set; }
    public override bool Equals(object obj)
    {
        var t = obj.GetType();
        foreach (var p in t.GetProperties())
        {
            if (t.GetProperty(p.Name).GetValue(obj, null) != t.GetProperty(p.Name).GetValue(this, null))
                return false;
        }
        return true;
    }
}
rdkleine