简体   繁体   English

Distinct 不适用于 IEquatable<t></t>

[英]Distinct is not working with IEquatable<T>

I have a class Bar that looks like this:我有一个 class Bar,看起来像这样:

public class Bar : IEquatable<Bar>
{
    public string Stringbar1{ get; set; }
    public string Stringbar2{ get; set; }
    public string Stringbar3{ get; set; }
    public string Stringbar4{ get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    public EnumFoo1 Enumfoo1{ get; set; }

    public bool IsBar{ get; set; }
    public List<string> StringBars{ get; set; }
    [BsonSerializer(SerializerType = typeof(NullableDateTimeOffsetToUtcSerializer))]
    public DateTimeOffset? FooDate{ get; set; }
    public string Stringbar5{ get; set; }
    [JsonConverter(typeof(StringEnumConverter))]
    public EnumFoo2 EnumFoo2 { get; set; }
    public string StringBar6{ get; set; }
    public int Foo{ get; set; }
 
    public Bar()
    {
        EnumFoo1= EnumFoo1.Unknown;
        EnumFoo2= EnumFoo2.Other;
        StringBars= new List<string>();
    }

 public bool Equals(Bar other)
    {
        if (other == null)
        {
            return false;
        }

        return Stringbar1 == other.Stringbar1&& Stringbar2== other.Stringbar2 && Stringbar3== other.Stringbar3 && Stringbar4== other.Stringbar4 && EnumFoo1== other.EnumFoo1 && IsBar== other.IsBar&&  BothNullOrEquals(StringBars,other.StringBars) && StringBar5==other.StringBar5&& FooDate== other.FooDate && ContractType == other.ContractType && LotNumber == other.LotNumber && Rank == other.Rank;
    }


    public override int GetHashCode()
    {
        var stringbar1Hashcode = Stringbar1== null ? 0 : Stringbar1.GetHashCode();
        var stringbar2HashCode = Stringbar2== null ? 0 : Stringbar2.GetHashCode();
        var stringbar3CodeHashCode = Stringbar3== null ? 0 : Stringbar3.GetHashCode();
        var EnumFoo1HashCode =  EnumFoo1.GetHashCode();
        var Stringbar4HashCode = Stringbar4== null ? 0 : Stringbar4.GetHashCode();
        var isBarHashCode =  IsBar.GetHashCode();
        var strtingBarsHashCode = StringBars== null ? 0 : StringBars.GetHashCode();
        var stringbar5HashCode = Stringbar5== null ? 0 : Stringbar5.GetHashCode();
        var fooDateHashCode = FooDate== null ? 0 : FooDate.GetHashCode();
        var enumFoo2HashCode= EnumFoo2.GetHashCode();
         var stringBar6HasCode = StringBar6== null ? 0 : StringBar6.GetHashCode();
        var fooHashCode= Foo.GetHashCode();
        return stringbar1Hashcode ^ stringbar2HashCode ^ stringbar3CodeHashCode ^ EnumFoo1HashCode ^ Stringbar4HashCode ^ isBarHashCode ^ strtingBarsHashCode ^ stringbar5HashCode ^ fooDateHashCode ^ enumFoo2HashCode ^ stringBar6HasCode  ^ fooHashCode ;
    }
    
    
    public static bool BothNullOrEquals<T>(IEnumerable<T> left, IEnumerable<T> right)
    {
        if (left == null && right == null)
        {
            return true;
        }
        if (left != null && right != null)
        {
            return left.SequenceEqual(right);
        }
        return false;
    }
}

Equals is working as expected but it seems that I am missing something when it comes to GetHashCode cause extension methods like LINQ Distinct are not working as expected. Equals 按预期工作,但在 GetHashCode 方面我似乎遗漏了一些东西,因为 LINQ Distinct 等扩展方法未按预期工作。 and I know that Distinct uses the GetHashCode method to compare references so any idea what am I doing wrong?而且我知道 Distinct 使用 GetHashCode 方法来比较引用所以知道我做错了什么吗?

The problem I can see is in the我能看到的问题是

var strtingBarsHashCode = StringBars== null ? 0 : StringBars.GetHashCode();

Please, note that for List<string> StringBars HashCode is reference based : hash codes are guaranteed to be equal if StringBars share the same reference only.请注意,对于List<string> StringBars HashCode 是基于引用的:如果StringBars共享相同的引用,则 hash 代码保证相等。 However, you compare these collections by more relaxing scheme:但是,您可以通过更轻松的方案来比较这些 collections:

BothNullOrEquals(StringBars, other.StringBars)

So, StringBars doesn't have to share the same reference to be equal, they should have equal items only .因此, StringBars不必共享相同的引用才能相等,它们应该只有相等的项 Note that GetHashCode must not return different codes for equal instances.请注意, GetHashCode不得为相同的实例返回不同的代码。

Don't make GetHashCode that elaborated;不要制作详细说明的GetHashCode please, note, that GetHashCode should be a fast estimation of Equals ;请注意, GetHashCode应该是对Equals快速估计; to be so 2.. 3 selective properties are enough:如此2.. 3选择性属性就足够了:

public override int GetHashCode() {
  // Let .Net check for null and combine hash codes for you
  return HashCode.Combine(Stringbar1, Stringbar2, Stringbar3);
}

Edit: If you can't use HashCode.Combine , well let it be ^ , but, please, don't put many fields and properties into GetHashCode just a few the most selective ones:编辑:如果您不能使用HashCode.Combine ,那么就让它成为^ ,但是,请不要将许多字段和属性放入GetHashCode中,只是一些最有选择性的:

public override int GetHashCode() {
  // Let .Net check for null and combine hash codes for you
  return (Stringbar1?.GetHashCode() ?? 0) ^
         (Stringbar2?.GetHashCode() ?? 0) ^
         (Stringbar3?.GetHashCode() ?? 0);
}

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

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