等于,GetHashCode和Operators覆盖IEquatable实现中未被调用

时间:2016-07-26 21:29:24

标签: c# linq equals iequalitycomparer iequatable

我正在尝试实现IEqueatable,因此我可以在自定义类型LINQ查询中使用 .Except

自定义类型代码如下所示:

public class Case : IEquatable<Case>
    {
        [Key]
        public int Id { get; set; }

        //More properties
        [...]      

        public bool Equals(Case other)
        {
            // Check whether the compared object references the same data.
            if (ReferenceEquals(this, other)) return true;

            // Check whether the compared object is null.
            if (ReferenceEquals(other, null)) return false;

            // Check whether the objects’ properties are equal.
            return Id.Equals(other.Id);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Case;
            // Check whether the compared object references the same data.
            if (ReferenceEquals(this, other)) return true;

            // Check whether the compared object is null.
            if (ReferenceEquals(other, null)) return false;

            // Check whether the objects’ properties are equal.
            return Id.Equals(other.Id);
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }

        public static bool operator ==(Case case1, Case case2)
        {
            if ((object)case1 == null || (object)case2 == null)
                return Equals(case1, case2);
            return case1.Equals(case2);

        }

        public static bool operator !=(Case case1, Case case2)
        {
            if ((object)case1 == null || (object)case2 == null)
                return !Equals(case1, case2);
            return !case1.Equals(case2);
        }
    }

我在Equals方法中添加了throw new NotImplementedException();,但它永远不会被调用。

我遵循了此处显示的约定: https://msdn.microsoft.com/en-us/library/ms131190.aspx

在这里 https://blogs.msdn.microsoft.com/csharpfaq/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types/

但没有成功。

修改

以下是调用Except方法的代码:

 if (Checkset(set))
                    {
                        var subset = GetPowerSet(set);
                        var newset = powerset.Except(subset);
                    }

powersetsubset都是Case的数组。

4 个答案:

答案 0 :(得分:0)

在尝试使用linq查询之前,我建议您使用更简单的方法。即。

var case1_1 = new Case() { Id = 1 };
var case1_2 = new Case() { Id = 1 };

var areEqual = case1_1 == case1_2;

有了这个测试,这些是我能想到为什么你没有达到那个例外的原因:

  1. 您有两个Equals方法,而您只从其中一个方法中抛出异常。
  2. 您比较过的2个对象具有相同的Id。如果GetHashCode的结果不同,则甚至可能尝试来比较这些值。
  3. 发现例外情况

答案 1 :(得分:0)

我有兴趣知道你是否尝试捕获Equals的两个重载...从你的代码中弹出的唯一一件事是你有重复的实现来检查相等性。理想情况下,你只能在一个地方做到这一点。

以下是一个示例实现...您将EntityBase替换为Case ...

  /// <summary>
  ///    Indicates whether the current object is equal to another object of the same type.
  /// </summary>
  /// <returns> true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false. </returns>
  /// <param name="other"> An object to compare with this object. </param>
  public bool Equals( EntityBase other ) {
     return !ReferenceEquals(other, null)
            && Id.Equals(other.Id);
  }

  /// <summary>
  ///    Serves as a hash function for a particular type.
  /// </summary>
  /// <returns> A hash code for the current <see cref="T:System.Object" />. </returns>
  /// <filterpriority> 2 </filterpriority>
  public override int GetHashCode() {
     return Id.GetHashCode();
  }

  /// <summary>
  ///    Determines whether the specified <see cref="T:System.Object" /> is equal to the current <see cref="T:System.Object" />.
  /// </summary>
  /// <returns> true if the specified object is equal to the current object; otherwise, false. </returns>
  /// <param name="obj"> The object to compare with the current object. </param>
  /// <filterpriority> 2 </filterpriority>
  public override bool Equals( object obj ) {
     return Equals(obj as EntityBase);
  }

  /// <summary>
  ///    Determines if the <paramref name="left" /> instance is considered equal to the <paramref name="right" /> object.
  /// </summary>
  /// <param name="left"> The instance on the left of the equality operator. </param>
  /// <param name="right"> The instance on the right of the equality operator. </param>
  /// <returns> True if the instances are considered equal, otherwise false. </returns>
  public static bool operator ==( EntityBase left, EntityBase right ) {
     return ReferenceEquals(left, null)
        ? ReferenceEquals(right, null)
        : left.Equals(right);
  }

  /// <summary>
  ///    Determines if the <paramref name="left" /> instance is considered unequal to the <paramref name="right" /> object.
  /// </summary>
  /// <param name="left"> The instance on the left of the inequality operator. </param>
  /// <param name="right"> The instance on the right of the inequality operator. </param>
  /// <returns> True if the instances are considered unequal, otherwise false. </returns>
  public static bool operator !=( EntityBase left, EntityBase right ) {
     return !(left == right);
  }

答案 2 :(得分:0)

如果你只打电话给:

var exceptList = list1.Except(list2);

没有返回任何列表,要执行枚举Except结果所需的比较,例如使用foreach:

foreach(var listElement in exceptList) 
{
    //...
}

然后调用GetHashCode和Equals方法。

修改: 此代码执行以下两个列表:

    static void Main(string[] args)
    {
        List<MyClass> list1 = new List<MyClass>();

        MyClass myClass1 = new MyClass() {Id = 1};
        MyClass myClass2 = new MyClass() {Id = 2};

        list1.Add(myClass1);
        list1.Add(myClass2);

        List<MyClass> list2 = new List<MyClass>();
        list2.Add(myClass1);

        var exceptList = list1.Except(list2);

        foreach (var myClass in exceptList)
        {
            Console.WriteLine(myClass.Id);
        }
    }


    public class MyClass : IEquatable<MyClass>
    {
        public int Id { get; set; }

        public bool Equals(MyClass other)
        {
            return Id == other.Id;
        }

        public override int GetHashCode()
        {
            return Id;
        }
    }

此代码在控制台中打印“2”

答案 3 :(得分:0)

Equals仅在必要时调用。处理IEquatable<T>实现的所有LINQ方法首先使用(并存储)它们处理的对象的哈希码。如果两个对象具有相同的哈希码,则这些方法仅调用Equals

在您的数据中,没有相同Id的情况,因此无需拨打Equals

这可以通过一个例子轻松证明。如果您有三个列表:

var list1 = new List<Case>
{
    new Case{ Id = 1 },
    new Case{ Id = 2 },
    new Case{ Id = 3 }
};
var list2 = new List<Case>
{
    new Case{ Id = 4 },
    new Case{ Id = 5 },
    new Case{ Id = 6 }
};
var list3 = new List<Case>
{
    new Case{ Id = 1 },
    new Case{ Id = 5 },
    new Case{ Id = 6 }
};

然后是以下语句(在EqualsGetHashCode中有一些跟踪语句,而后者只是返回Id)...

list1.Except(list2).ToList();

...将输出:

GetHashCode: 4
GetHashCode: 5
GetHashCode: 6
GetHashCode: 1
GetHashCode: 2
GetHashCode: 3

虽然声明......

list1.Except(list3).ToList();

...将输出:

GetHashCode: 1
GetHashCode: 5
GetHashCode: 6
GetHashCode: 1
Equals: 1 - 1
GetHashCode: 2
GetHashCode: 3