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

时间:2014-08-20 11:04:39

标签: c# immutability gethashcode value-objects

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

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是一个不可变的value object,我希望它的行为像一个真正的价值对象:

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方法
  • 使用类型的哈希码
  • 避免空对象(添加字段)

但是没有通过搜索确认的假设

那么,你会做什么?

3 个答案:

答案 0 :(得分:3)

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

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

    private FirstRequestHeader()
    {

    }
}

答案 1 :(得分:2)

  

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

如果您希望将两个“相同”的对象视为相等(并且没有字段或您的实例相同),这绝对是可行的方法。

添加一个新字段,我假设您不会以任何有意义的方式进行修改,结果相同,只是过于复杂。对于其他两种方法也可以这样说。

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

答案 2 :(得分:1)

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

    public class FirstRequestHeader
    {
        public override int GetHashCode()
        {
            return this.GetType().GetHashCode();
        }
    }