简体   繁体   English

linq&distinct,实现equals和gethashcode

[英]linq & distinct, implementing the equals & gethashcode

so I'm trying to make this work and I can't seem to know why it doesn't work 所以我正在努力使这项工作,我似乎无法知道为什么它不起作用

demo code; 演示代码;

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

}
}

anyone could spot my error(s) ? 任何人都可以发现我的错误?

You need to override the Equals(object) method: 您需要覆盖Equals(object)方法:

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

The object.Equals method (unlike EqualityComparer<T>.Default ) does not use the IEquatable interface. object.Equals方法(与EqualityComparer<T>.Default )不使用IEquatable接口。 Therefore, when you write object.Equals(c1, other.c1) , it doesn't call your Child.Equals(Child) method. 因此,当您编写object.Equals(c1, other.c1) ,它不会调用您的Child.Equals(Child)方法。

You don't absolutely need to do that for parent as well, but you really should. parent也不一定非常需要这样做,但你真的应该这样做。

Either you do what SLaks suggests, or you use EqualityComparer<child>.Default in your parent class to use your IEquatable<child> implementation: 您可以执行SLaks建议的操作,也可以在parent类中使用EqualityComparer<child>.Default来使用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);
 }

When adding the calculating the hash you might want to try something like 在添加计算哈希时,您可能想要尝试类似的东西

hash ^= id.GetHashCode();

Not sure if that is what is causing your issue. 不确定这是否是导致您的问题的原因。

There are several things to get right here. 这里有几件事要做。 If I'm going to implement any aspect of equality in a class such as GetHashCode , overriding == or IEquatable , I always use the following pattern. 如果我要在GetHashCodeIEquatable ==或IEquatable等类中实现相等的任何方面,我总是使用以下模式。

  1. Override Equals 覆盖等于
  2. Override GetHashCode 覆盖GetHashCode
  3. Implement IEquatable<T> which means implementing Equals(T) 实现IEquatable<T> ,这意味着实现Equals(T)
  4. Implement != 实施!=
  5. Implement == 实施==

So, if I had a class named ExpiryMonth with properties Year and Month, this is how that implementation would look. 所以,如果我有一个名为ExpiryMonth的类具有属性Year和Month,那么这就是该实现的外观。 It's a fairly mindless task now to adapt for other types of classes. 现在适应其他类型的课程是一项相当盲目的任务。

I have based this pattern on several other stackoverflow answers which all deserve credit, but which I haven't tracked along the way. 我已将此模式基于其他几个stackoverflow答案,这些答案都值得赞扬,但我一直没有跟踪。

By always implementing all of these elements together, it ensures proper equality operations in a variety of contexts including dictionaries and Linq operations. 通过始终将所有这些元素一起实现,它确保在各种上下文中进行适当的相等操作,包括字典和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;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM