这生成的哈希值为什么是0?

huangapple go评论67阅读模式
英文:

Why is this generating hash of 0?

问题

以下是您要翻译的代码部分:

我正在尝试使用一些代码,该代码将根据对象内所有属性的值生成哈希码,但以下代码返回`HashCodeOnProperties`的值为0

Console.WriteLine("Hello, World!");

var request = new Request()
{

    NorthEastLatitude = 43.13306116240615,
    NorthEastLongitude = -80.9355926513672,
    NorthWestLatitude = 43.13306116240615,
    NorthWestLongitude = -81.573486328125014,
    SouthEastLatitude = 42.831667202614092,
    SouthEastLongitude = -80.9355926513672 ,
    SouthWestLatitude = 42.831667202614092,
    SouthWestLongitude = -81.573486328125014
};

var hash = request.GetHashCodeOnProperties();
Console.WriteLine(hash);

Console.ReadKey();


public class Request
{
    public double? SouthWestLatitude { get; set; }
    public double? SouthWestLongitude { get; set; }
    public double? NorthEastLatitude { get; set; }
    public double? NorthEastLongitude { get; set; }


    public double? SouthEastLatitude { get; set; }
    public double? SouthEastLongitude { get; set; }
    public double? NorthWestLatitude { get; set; }
    public double? NorthWestLongitude { get; set; }

}
public static class HashCodeByPropertyExtensions
{
    public static int GetHashCodeOnProperties<T>(this T inspect)
    {
        return inspect.GetType().GetProperties().Select(o => o.GetValue(inspect)).GetListHashCode();
    }

    public static int GetListHashCode<T>(this IEnumerable<T> sequence)
    {
        return sequence
            .Where(item => item != null)
            .Select(item => item.GetHashCode())
            .Aggregate((total, nextCode) => total ^ nextCode);
    }
}

希望这对您有所帮助。如果您需要进一步的解释或帮助,请随时告诉我。

英文:

I am trying to use some code that will generate hashcode based on the value of all properties inside an object, but the following returns a 0 for the HashCodeOnProperties

Console.WriteLine(&quot;Hello, World!&quot;);

var request = new Request()
{

    NorthEastLatitude = 43.13306116240615,
    NorthEastLongitude = -80.9355926513672,
    NorthWestLatitude = 43.13306116240615,
    NorthWestLongitude = -81.573486328125014,
    SouthEastLatitude = 42.831667202614092,
    SouthEastLongitude = -80.9355926513672 ,
    SouthWestLatitude = 42.831667202614092,
    SouthWestLongitude = -81.573486328125014
};

var hash = request.GetHashCodeOnProperties();
Console.WriteLine(hash);

Console.ReadKey();


public class Request
{
    public double? SouthWestLatitude { get; set; }
    public double? SouthWestLongitude { get; set; }
    public double? NorthEastLatitude { get; set; }
    public double? NorthEastLongitude { get; set; }


    public double? SouthEastLatitude { get; set; }
    public double? SouthEastLongitude { get; set; }
    public double? NorthWestLatitude { get; set; }
    public double? NorthWestLongitude { get; set; }

}
public static class HashCodeByPropertyExtensions
{
    public static int GetHashCodeOnProperties&lt;T&gt;(this T inspect)
    {
        return inspect.GetType().GetProperties().Select(o =&gt; o.GetValue(inspect)).GetListHashCode();
    }

    public static int GetListHashCode&lt;T&gt;(this IEnumerable&lt;T&gt; sequence)
    {
        return sequence
            .Where(item =&gt; item != null)
            .Select(item =&gt; item.GetHashCode())
            .Aggregate((total, nextCode) =&gt; total ^ nextCode);
    }
}

答案1

得分: 2

你在没有“offset”的情况下执行异或操作,因此这将导致相同的值互相抵消(异或是可交换和可结合的,所以42 ^ 77 ^ 42 ^ 77等同于42 ^ 42 ^ 77 ^ 77,显然是0)。你可以像这样做:

public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
    var hash = 17;
    return sequence
        .Where(item => item != null)
        .Select(item => item.GetHashCode())
        .Aggregate(hash, (total, nextCode) => unchecked(total * 23 + nextCode));
}

或者使用 System.HashCode(自.NET Core 2.1起可用)执行聚合操作:

public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
    var hashCode = new HashCode();
    return sequence
        .Where(item => item != null)
        .Select(item => item.GetHashCode())
        .Aggregate(new HashCode(), (code, i) =>
        {
             hashCode.Add(i);
             return hashCode;
        })
        .ToHashCode();
}

P.S.

计算哈希码应该是快速操作,而反射通常不是很快的方法。考虑使用源代码生成器或一些动态代码编译与表达式树(参见例如这个这个答案以获取一些灵感),或者切换到使用自动生成相等成员的record

英文:

You are xoring values without "offset", so this will result in same values canceling each other out (exclusive or is associative and commutative so 42 ^ 77 ^ 42 ^ 77 is equivalent to 42 ^ 42 ^ 77 ^ 77 which is clearly is 0). You can do something like:

public static int GetListHashCode&lt;T&gt;(this IEnumerable&lt;T&gt; sequence)
{
    var hash = 17;
    return sequence
        .Where(item =&gt; item != null)
        .Select(item =&gt; item.GetHashCode())
        .Aggregate(hash, (total, nextCode) =&gt; unchecked(total*23 + nextCode));
}

Or use System.HashCode (available since .NET Core 2.1) to perform aggregation:

public static int GetListHashCode&lt;T&gt;(this IEnumerable&lt;T&gt; sequence)
{
    var hashCode = new HashCode();
    return sequence
        .Where(item =&gt; item != null)
        .Select(item =&gt; item.GetHashCode())
        .Aggregate(new HashCode(), (code, i) =&gt;
        {
             hashCode.Add(i);
             return hashCode;
        })
        .ToHashCode();
}

P.S.

Calculating hashcode should be fast operation, while reflection is usually not very fast approach. Consider using source generators or some dynamic code compilation with expression trees (see for example this or this answers for some inspiration) or switching to using record's which have equality members autogenerated.

答案2

得分: 1

只是一个附带图片的评论。如果您的 Request 类应始终表示地球的一个环形扇区,其边界遵循经度和纬度线,那么您只需要存储两个直径相对的角的坐标。

这生成的哈希值为什么是0?

这生成的哈希值为什么是0?

英文:

Just a comment with images. If your Request class is supposed to always represent an annulus sector of the Earth whose boundaries follow lines of longitude and latitude, then you need only store coordinates for two diametrically opposite corners.

这生成的哈希值为什么是0?

这生成的哈希值为什么是0?

答案3

得分: 1

@GuruStron提供了正确答案,我只想包含一个更强大的聚合哈希码函数,基于Visual Studio生成的代码。

public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
    unchecked
    {
        return sequence.Where(item => item != null)
          .Aggregate(-1817952719, 
            (hc, item) => (-1521134295) * hc + item.GetHashCode()); 
    }
}

-1817952719-1521134295的值只是用来替代1723的大型复杂数字,以减少碰撞的可能性。还需要将操作包装在unchecked中以避免整数溢出异常。

这些值是我在Visual Studio中执行生成GetHashCode()命令时从建议的代码中获取的。

英文:

@GuruStron has the correct answer, I just want to include a more robust aggregate hash code function based on code generated by VS.

public static int GetListHashCode&lt;T&gt;(this IEnumerable&lt;T&gt; sequence)
{
    unchecked
    {
        return sequence.Where(item =&gt; item != null)
          .Aggregate(-1817952719, 
            (hc, item) =&gt; (-1521134295) * hc + item.GetHashCode()); 
    }
}

The values of -1817952719 and -1521134295 are just large fancy numbers to replace 17 and 23 in order to reduce changes for a collision. Also enclosing the operation in unchecked is required to avoid any integer overflow exceptions.

--

I got the values from the suggested code when I issue a generate GetHashCode() command in Visual Studio.

这生成的哈希值为什么是0?

huangapple
  • 本文由 发表于 2023年4月13日 19:07:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76004705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定