具有相同元素的两个列表不相等。为什么?

时间:2016-07-01 18:08:51

标签: c# .net

我有以下内容:

  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);

即使两个列表包含彼此相等的项目,r变量也为false。 OrdeRule类实现IEquality。请注意,当Direction和Property都相等时,两个OrderRules是相等的。

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);

  }

}

我错过了什么?

4 个答案:

答案 0 :(得分:7)

检查两个列表是否相等并不意味着检查它们是否包含相同的项目。

如果你这样做:

var a = new List<OrderRule>();
var b = new List<OrderRule>();
var r = a.Equals(b); //false
即使两个列表中包含相同的项目,

r也始终为false。这是因为你没有检查列表的内容。您实际上正在检查ab是否都指向同一个对象。但a是一个对象而b是另一个对象。

如果您这样做,r将是真的:

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

如果您有两个列表,并且想要查看它们是否包含相同顺序的相同项目,则可以执行以下操作:

var r = a.SequenceEquals(b);

在您的问题r中的示例中,trueEquals,因为您在OrderRule上覆盖了OrderRule,因此一个列表中的项目被视为& #34;等于&#34;到另一个的项目。

知道了 - 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); } 中的平等检查被破坏了。

return Equals(obj as IncludeRule)

我认为return Equals(obj as OrderRule)代替$("#ddhintgrid > .k-grid-content > table > tbody > tr:not(:first, :last)").hover(function () {...});而不是<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView_link_name" android:layout_width="wrap_content" android:layout_height="wrap_content" ... <EditText ... <TextView ... <EditText ... <ImageButton ... </RelativeLayout>

答案 1 :(得分:4)

您的代码正在测试它们是否是相同的列表。如果它们具有相同的内容则不会。

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

如果你想比较内容,那么使用linq的SequenceEqual

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

答案 2 :(得分:1)

首先,每当使用new关键字或创建新对象时,对象的引用或地址都存储在变量中。 equals也比较变量的值。

现在你已经覆盖了OrderRule的等于函数。因此,如果你在两个OrderRule上做等于你将在覆盖的等于函数内进行比较时得到结果。

但是现在想想这是什么List<OrderRule>它只是一个通用类。因此,equals将再次检查包含引用的变量的值,因为它们不同,所以当您比较它们时,它们将无法生效。 List也实现了与未被覆盖的对象相同的equals。因此,我更喜欢的一种方法是创建扩展。

public static class Extensions
{
    public static bool Equal<T>(this List<T> x, List<T> y)
    {
        bool isEqual = true;
        if (x == null ^ y == null)
        {
            isEqual = false;
        }
        else if (x == null && y == null)
        {
            isEqual = true;
        }
        else if (x.Equals(y))
        {
            isEqual = true;
        }
        else if (x.Count != y.Count)
        {
            isEqual = false;
        }
        else
        {
            //This logic can be changed as per your need.
            //Here order of the list matters!
            //You can make one where order doesn't matter
            for (int i = 0; i < x.Count; i++)
            {
                if (!x[i].Equals(y[i]))
                {
                    break;
                }
            }

        }
        return isEqual;
    }
}

答案 3 :(得分:0)

这样做是为了比较参考而不是对象。所以你得到了不平等。