linq&不同的,实现平等和GetHashCode的

时间:2011-01-24 20:39:39

标签: c# .net linq

所以我正在尝试做这项工作而我似乎无法知道为什么它不起作用

演示代码;

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        var myVar = new List<parent >();
        myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } });
        myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } });

        var test = myVar.Distinct();

        Console.ReadKey();

    }
}


public class parent : IEquatable<parent>
{
    public String id { get;set;}
    public String blah1 { get; set; }
    public child c1 { get; set; }

    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            // Suitable nullity checks etc, of course :)
            hash = hash * 23 + id.GetHashCode();
            hash = hash * 23 + blah1.GetHashCode();
            hash = hash * 23 + (c1 == null ? 0 : c1.GetHashCode());
            return hash;
        }
    }

    public bool Equals(parent other)
    {
        return object.Equals(id, other.id) &&
            object.Equals(blah1, other.blah1) &&
            object.Equals(c1, other.c1);
    }

}

public class child : IEquatable<child>
{
    public String blah2 { get; set; }
    public String blah3 { get; set; }

    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            // Suitable nullity checks etc, of course :)
            hash = hash * 23 + blah2.GetHashCode();
            hash = hash * 23 + blah3.GetHashCode();
            return hash;
        }
    }

    public bool Equals(child other)
    {
        return object.Equals(blah2, other.blah2) &&
            object.Equals(blah3, other.blah3);
    }

}
}

任何人都可以发现我的错误?

4 个答案:

答案 0 :(得分:5)

您需要覆盖Equals(object)方法:

public override bool Equals(object obj) {
    return Equals(obj as parent);
}

object.Equals方法(与EqualityComparer<T>.Default不同)不使用IEquatable接口。因此,当您撰写object.Equals(c1, other.c1)时,它不会调用您的Child.Equals(Child)方法。

您也不一定非常需要为parent执行此操作,但真的应该。

答案 1 :(得分:3)

您执行SLaks建议的操作,或者使用EqualityComparer<child>.Default课程中的parent来使用IEquatable<child>实施:

  public bool Equals(parent other)
  {
   return object.Equals(id, other.id) &&
    object.Equals(blah1, other.blah1) &&
    EqualityComparer<child>.Default.Equals(c1, other.c1);
 }

答案 2 :(得分:0)

添加计算哈希值时,您可能需要尝试类似

的内容

hash ^= id.GetHashCode();

不确定这是否是导致您出现问题的原因。

答案 3 :(得分:0)

这里有几件事要做。如果我要在诸如GetHashCode,覆盖==或IEquatable的类中实现相等的任何方面,我总是使用以下模式。

  1. 覆盖等于
  2. 覆盖GetHashCode
  3. 实施IEquatable<T>,这意味着实施Equals(T)
  4. 实施!=
  5. 实施==
  6. 所以,如果我有一个名为ExpiryMonth的类,其属性为Year和Month,那么这就是实现的样子。现在适应其他类型的课程是一项相当盲目的任务。

    我已将此模式基于其他几个stackoverflow答案,这些答案都值得赞扬,但我一直没有跟踪。

    通过始终将所有这些元素一起实现,它确保在各种上下文中进行适当的相等操作,包括字典和Linq操作。

        public static bool operator !=(ExpiryMonth em1, ExpiryMonth em2)
        {
            if (((object)em1) == null || ((object)em2) == null)
            {
                return !Object.Equals(em1, em2);
            }
            else
            {
                return !(em1.Equals(em2));
            }
        }
        public static bool operator ==(ExpiryMonth em1, ExpiryMonth em2)
        {
            if (((object)em1) == null || ((object)em2) == null)
            {
                return Object.Equals(em1, em2);
            }
            else
            {
                return em1.Equals(em2);
            }
        }
        public bool Equals(ExpiryMonth other)
        {
            if (other == null) { return false; }
            return Year == other.Year && Month == other.Month;
        }
        public override bool Equals(object obj)
        {
            if (obj == null) { return false; }
            ExpiryMonth em = obj as ExpiryMonth;
            if (em == null) { return false; }
            else { return Equals(em); }
        }
        public override int GetHashCode()
        {
            unchecked // Overflow is not a problem
            {
                var result = 17;
                result = (result * 397) + Year.GetHashCode();
                result = (result * 397) + Month.GetHashCode();
                return result;
            }
        }