Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two lists with same elements are not equal. Why?

Tags:

c#

.net

I have the following:

  var a = new List<OrderRule> {
    new OrderRule("name", OrderDirection.Ascending),
    new OrderRule("age", OrderDirection.Descending)
  };


  var b = new List<OrderRule> {
    new OrderRule("name", OrderDirection.Ascending),
    new OrderRule("age", OrderDirection.Descending)
  };

  var r = a.Equals(b);

The r variable is false even if the two lists include items which are equal to each other. The OrdeRule class implements IEquality. Note that two OrderRules are equal when both Direction and Property are equal.

public enum OrderDirection { ASC, DESC }

public class OrderRule : IEquatable<OrderRule> {

  public OrderDirection Direction { get; }
  public String Property { get; }

  public OrderRule(String property, OrderDirection direction) {
    Direction = direction;
    Property = property;
  }

  public Boolean Equals(OrderRule other) {

    if (other == null)
      return false;

    return Property.Equals(other.Property) && Direction.Equals(other.Direction);

  }

  public override Boolean Equals(Object obj) {

    if (ReferenceEquals(null, obj))
      return false;

    if (ReferenceEquals(this, obj))
      return true;

    if (obj.GetType() != GetType())
      return false;

    return Equals(obj as IncludeRule);

  }

  public override Int32 GetHashCode() {

    return HashCode.Of(Property).And(Direction);

  }

}

What am I missing?

like image 792
Miguel Moura Avatar asked Jul 01 '16 18:07

Miguel Moura


2 Answers


Checking to see if two lists are equal doesn't mean checking to see if they both contain the same items.

If you do this:

var a = new List<OrderRule>();
var b = new List<OrderRule>();
var r = a.Equals(b); //false

r will always be false, even if the two lists have the same items in them. That's because you're not checking the contents of the lists. You're actually checking to see if both a and b refer to the same object. But a is one object and b is another.

If you did this, r would be true:

var a = new List<OrderRule>();
var b = a;
var r = a.Equals(b) //true

If you have two lists and you want to see if they contain the same items in the same order, you could do this:

var r = a.SequenceEquals(b);

In the example in your question r would be true because you're overriding Equals on OrderRule, so the items in the one list are considered "equal" to the items in the other.


Got it - your equality check in OrderRule is broken.

public override Boolean Equals(Object obj) {
if (ReferenceEquals(null, obj))
  return false;

if (ReferenceEquals(this, obj))
  return true;

if (obj.GetType() != GetType())
  return false;

return Equals(obj as IncludeRule);
}

I think instead of return Equals(obj as IncludeRule) you mean return Equals(obj as OrderRule).

like image 56
Scott Hannen Avatar answered Oct 15 '22 18:10

Scott Hannen


your code is testing to see if they are the same list. not if they have the same contents.

a.Equals(b); // false
var d = a;
d.Equals(a); // true

if you want to compare the contents then use linq's SequenceEqual

https://msdn.microsoft.com/en-us/library/bb348567(v=vs.100).aspx

like image 31
pm100 Avatar answered Oct 15 '22 17:10

pm100