C# –如何重写 List的 GetHashCode以 T 为记录来计算 ETag

发布于 2025-01-09 00:03:35 字数 1114 浏览 1 评论 0原文

对于 NetCore Web API GET 方法,我需要计算返回的 List 的 ETag。 T 是仅保存原始类型的记录 形式的 DTO。

我想计算列表的哈希值。我正在搜索有关如何实现 GetHashCode() 的信息,但找不到任何信息。 object.GetHashCode() 的文档 不声明有关列表或集合的任何信息。通过代码的结果,我观察到每次运行时相同的列表数据都会创建不同的哈希码。我得出的结论是,GetHashCode() 使用引用类型项的指针值。

recordGetHashCode() 计算每个成员值的哈希码。因此,我通过循环列表项创建了列表哈希码:

List<GetGroupsDTO> dtoList = commandResult.Value;
int hash = 17;
foreach(GetGroupsDTO dto in dtoList)
{
   hash = hash * 23 + dto.GetHashCode();
}
string eTagPayload = hash.ToString().SurroundWithDoubleQuotes();

当然,我不想对每个 List 都执行此操作。我想重写 GetHashCode(),但我正在努力解决这个问题。我不知道如何覆盖通用列表。我可以派生一个新类 DTOList,在其中可以重写 GetHashCode()。但这会导致其他地方变得更加复杂。由于 EFCore Set 查询的结果填充列表,我需要一个自定义转换器,然后需要一个自定义序列化器来返回 Web API 中的列表。

因此,我想知道是否应该为 List 创建一个扩展方法,或者只是一个以 List 作为参数的函数。还有其他选项可以计算 ETag 吗?如何有效计算 DTO 对象列表的 ETag?

For a NetCore Web API GET method I need to caluclate the ETag for a returned List<T>. T is the DTO in the form of a record that holds only primitive types.

I wanted to calculate a hash of the list. I was searching for information about how GetHashCode() is implemented, but couldn't find any information. The documentation of object.GetHashCode()
doesn't state any information about lists or collections. By the results of the code I observed that on each run the same list data creates a different hash code. I concluded that GetHashCode() uses the pointer values for reference type items.

GetHashCode() of record calculates the hash code per member value. Therefore I created the list hash code by looping over the list items:

List<GetGroupsDTO> dtoList = commandResult.Value;
int hash = 17;
foreach(GetGroupsDTO dto in dtoList)
{
   hash = hash * 23 + dto.GetHashCode();
}
string eTagPayload = hash.ToString().SurroundWithDoubleQuotes();

I don't want to do this for every List<T>, of course. I thought to override GetHashCode(), but I'm struggling with it. I don't know how to override it for the generic List. I could derive a new class DTOList where I can override GetHashCode(). But this leads to more complexity in other places. Since the result of an EFCore Set query fills the List I would need a custom converter and then a custom serializer to return the List in Web API.

Therefore I wonder if I rather should create an extension method for List or just a function that takes List as an argument. Is there any other option to calculate the ETag? How can I calculate the ETag for a list of DTO objects efficently?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫烠⑼条掵仅有一顆心 2025-01-16 00:03:35

一个小的扩展方法和 HashCode 可以帮助解决这个问题:

internal static class EnumerableExtensions {
    public static int GetCombinedHashCode<T>(this IEnumerable<T> source) => 
        source.Aggregate(typeof(T).GetHashCode(), (hash, t) => HashCode.Combine(hash, t));
}

使用 typeof(T).GetHashCode 播种哈希是相当任意的,但确保不同类型的空集合不会所有“看起来都相等”,因为它们通常也不会相等。这是否重要或什至是可取的将取决于您的情况。

当然,只有当 T 具有有意义的 GetHashCode 实现时,此结果才可用,但对于一般的哈希来说也是如此。为了更加安心,可以添加 where T : IEquatable 约束,尽管这不是涉及哈希的方法的标准方法。添加使用自定义 IEqualityComparer 进行哈希的功能留作练习。

A little extension method and HashCode could help with this:

internal static class EnumerableExtensions {
    public static int GetCombinedHashCode<T>(this IEnumerable<T> source) => 
        source.Aggregate(typeof(T).GetHashCode(), (hash, t) => HashCode.Combine(hash, t));
}

Seeding the hash with typeof(T).GetHashCode is a rather arbitrary, but ensures that empty collections of different types do not all "look equal", since they would not normally compare equal either. Whether this matters or is even desirable will depend on your scenario.

Of course the result of this is only usable if T has a meaningful GetHashCode implementation, but that's true of hashes in general. For extra peace of mind a where T : IEquatable<T> constraint could be added, although that's not the standard approach for methods involving hashes. Adding the ability to use a custom IEqualityComparer<T> for the hash is left as an exercise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文