Dumbo
Dumbo

Reputation: 14142

Comparing two instances of a class

I have a class like this

public class TestData
{
   public string Name {get;set;}
   public string type {get;set;}

   public List<string> Members = new List<string>();

   public void AddMembers(string[] members)
   {
      Members.AddRange(members);
   }   
}

I want to know if it is possible to directly compare to instances of this class to eachother and find out they are exactly the same? what is the mechanism? I am looking gor something like if(testData1 == testData2) //Do Something And if not, how to do so?

Upvotes: 19

Views: 88539

Answers (9)

Michał Jaroń
Michał Jaroń

Reputation: 624

In theory the IEquatable<> interface should be implemented but alternatively if performance is not most important, reflection may be used.

Below sample method for comparing objects using reflection:

static class CompareHelper
{
    public static bool Compare<A, B>(A a, B b)
    {
        if (Object.ReferenceEquals(a, b))
        {
            return true;
        }

        if (a == null || b == null)
        {
            return false;
        }

        if (!a.GetType().Equals(b.GetType()))
        {
            return false;
        }

        Type type = a.GetType();

        if (a is IEquatable<B> aEquatable)
        {
            if (!aEquatable.Equals(b))
            {
                return false;
            }
        }
        //else if (a is IComparable comparableA && b is IComparable comparableB) // optionally
        //{
        //    if (comparableA.CompareTo(comparableB) != 0)
        //    {
        //        return false;
        //    }
        //}
        else if (type.IsEnum)
        {
            if (!a.Equals(b))
            {
                return false;
            }
        }
        else if (type.IsClass)
        {
            foreach (var field in a.GetType().GetFields())
            {
                Type fieldType = field.FieldType;
                var aValue = field.GetValue(a);
                var bValue = field.GetValue(b);

                MethodInfo compareMethod = typeof(CompareHelper).GetMethod(nameof(CompareHelper.Compare));
                MethodInfo generic = compareMethod.MakeGenericMethod(fieldType, fieldType);
                var invokeResult = generic.Invoke(null, new object[] { aValue, bValue });
                bool invokeResultBool = (bool)invokeResult;
                if (!invokeResultBool)
                {
                    return false;
                }
            }
        }
        else
        {
            throw new InvalidOperationException("Compare: Type not supported: [" + type + "].");
        }
        return true;
    }
}

Upvotes: -1

Frederik Gheysels
Frederik Gheysels

Reputation: 56964

You should implement the IEquatable<T> interface on your class, which will allow you to define your equality-logic. Actually, you should override the Equals method as well.

public class TestData : IEquatable<TestData>
{
   public string Name {get;set;}
   public string type {get;set;}

   public List<string> Members = new List<string>();

   public void AddMembers(string[] members)
   {
      Members.AddRange(members);
   }   

  // Overriding Equals member method, which will call the IEquatable implementation
  // if appropriate.

   public override bool Equals( Object obj )
   {
       var other = obj as TestData;
       if( other == null ) return false;

       return Equals (other);             
   }

   public override int GetHashCode()
   {
      // Provide own implementation
   }


   // This is the method that must be implemented to conform to the 
   // IEquatable contract

   public bool Equals( TestData other )
   {
       if( other == null )
       {
            return false;
       }

       if( ReferenceEquals (this, other) )
       {
            return true;
       }

       // You can also use a specific StringComparer instead of EqualityComparer<string>
       // Check out the specific implementations (StringComparer.CurrentCulture, e.a.).
       if( EqualityComparer<string>.Default.Compare (Name, other.Name) == false )
       {
           return false;
       }
       ...

       // To compare the members array, you could perhaps use the 
       // [SequenceEquals][2] method.  But, be aware that [] {"a", "b"} will not
       // be considerd equal as [] {"b", "a"}

       return true;

   }

}

Upvotes: 27

roozbeh S
roozbeh S

Reputation: 1124

I see many good answers here but just in case you want the comparison to work like

if(testData1 == testData2) // DoSomething

instead of using Equals function you can override == and != operators:

public static bool operator == (TestData left, TestData right)
{
    bool comparison = true; //Make the desired comparison
    return comparison;
}

public static bool operator != (TestData left, TestData right)
{
    return !(left == right);
}

Upvotes: 2

Patrick McDonald
Patrick McDonald

Reputation: 65461

One way of doing it is to implement IEquatable<T>

public class TestData : IEquatable<TestData>
{
   public string Name {get;set;}
   public string type {get;set;}

   public List<string> Members = new List<string>();

   public void AddMembers(string[] members)
   {
      Members.AddRange(members);
   }

   public bool Equals(TestData other)
   {
        if (this.Name != other.Name) return false;
        if (this.type != other.type) return false;

        // TODO: Compare Members and return false if not the same

        return true;
   }
}


if (testData1.Equals(testData2))
    // classes are the same

You can also just override the Equals(object) method (from System.Object), if you do this you should also override GetHashCode see here

Upvotes: 9

Jon
Jon

Reputation: 437734

There are three ways objects of some reference type T can be compared to each other:

  1. With the object.Equals method
  2. With an implementation of IEquatable<T>.Equals (only for types that implement IEquatable<T>)
  3. With the comparison operator ==

Furthermore, there are two possibilities for each of these cases:

  1. The static type of the objects being compared is T (or some other base of T)
  2. The static type of the objects being compared is object

The rules you absolutely need to know are:

  • The default for both Equals and operator== is to test for reference equality
  • Implementations of Equals will work correctly no matter what the static type of the objects being compared is
  • IEquatable<T>.Equals should always behave the same as object.Equals, but if the static type of the objects is T it will offer slightly better performance

So what does all of this mean in practice?

As a rule of thumb you should use Equals to check for equality (overriding object.Equals as necessary) and implement IEquatable<T> as well to provide slightly better performance. In this case object.Equals should be implemented in terms of IEquatable<T>.Equals.

For some specific types (such as System.String) it's also acceptable to use operator==, although you have to be careful not to make "polymorphic comparisons". The Equals methods, on the other hand, will work correctly even if you do make such comparisons.

You can see an example of polymorphic comparison and why it can be a problem here.

Finally, never forget that if you override object.Equals you must also override object.GetHashCode accordingly.

Upvotes: 7

Glory Raj
Glory Raj

Reputation: 17701

Implement the IEquatable<T> interface. This defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances. More information here:

http://msdn.microsoft.com/en-us/library/ms131187.aspx

Upvotes: 1

user182630
user182630

Reputation: 574

First of all equality is difficult to define and only you can define as to what equality means for you

  1. Does it means members have same value
  2. Or they are pointing to same location.

Here is a discussion and an answer here

What is "Best Practice" For Comparing Two Instances of a Reference Type?

Upvotes: 1

DaveRead
DaveRead

Reputation: 3413

You will need to define the rules that make object A equal to object B and then override the Equals operator for this type.

http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

Upvotes: 1

Haris Hasan
Haris Hasan

Reputation: 30117

You can override the equals method and inside it manually compare the objects

Also take a look at Guidelines for Overloading Equals() and Operator ==

Upvotes: 1

Related Questions