重写没有字段的值对象的GetHashCode()

本文关键字:GetHashCode 对象 字段 重写 | 更新日期: 2023-09-27 18:18:45

有时我需要不带字段的值对象(消息头、模式等),例如:

abstract class RequestHeader
{
}
sealed class FirstRequestHeader : RequestHeader
{
}

我在以下方法中使用它们:

partial class Server
{
    private readonly IReadOnlyDictionary<RequestHeader, Action<object>> requestMap;
    public void ProcessRequest(RequestHeader header, object request)
    {
        requestMap[header](request);
    }
}

在这种情况下,GetHashCodeEquals方法的默认实现完全符合我的需要,因为我可以使用单例。

但是由于FirstRequestHeader是一个不可变的值对象,我希望它的行为像一个真正的值对象:

var a = new FirstRequestHeader();
var b = new FirstRequestHeader();
Console.WriteLine(a == b &&
    a.Equals(b) &&
    a.GetHashCode() == b.GetHashCode()); // False, but should be True

重写==操作符和Equals方法很容易。

但是在这种情况下重写GetHashCode方法的正确或推荐的方法是什么?

我可以期待一些答案(都有一些缺点):

  • 每种类型的硬码常量哈希码
  • 每次执行生成一个并保存在静态字段
  • 通过GetType方法使用类型的哈希码
  • 避免空对象(添加字段)

但是没有通过搜索

来确认假设。

你会怎么做?

重写没有字段的值对象的GetHashCode()

如果没有与类相关的数据,则只创建一个实例。

sealed class FirstRequestHeader : RequestHeader
{
    public static readonly FirstRequestHeader Value = new FirstRequestHeader();
    private FirstRequestHeader()
    {
    }
}

每种类型的硬码常量哈希码

如果您希望两个"相同"的对象被视为相等(并且没有字段或您的实例是相同的),这绝对是要走的路。

添加一个新字段,我假设您不会以任何有意义的方式修改它,结果相同,只是使它过于复杂。其他两种方法也是如此。

请注意,您可以选择任何值-您不需要担心不同类型之间可能的哈希码冲突,因此保持简单。

如果您希望所有实例具有相同的哈希码而不使用常量,您还可以使用类型为

的哈希码:
    public class FirstRequestHeader
    {
        public override int GetHashCode()
        {
            return this.GetType().GetHashCode();
        }
    }