代码之家  ›  专栏  ›  技术社区  ›  astef

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

  •  3
  • astef  · 技术社区  · 10 年前

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

    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);
        }
    }
    

    在这种情况下 GetHashCode Equals 方法完全符合我的需要,因为我可以使用单件。

    但从那时起 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
    

    最重要的 == 操作员和 等于 方法很简单。

    但什么是正确的或推荐的覆盖方式 方法 这种情况下的方法?

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

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

    但搜索没有证实任何假设

    那么,你会怎么做?

    3 回复  |  直到 10 年前
        1
  •  3
  •   ChaosPandion    10 年前

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

    sealed class FirstRequestHeader : RequestHeader
    {
        public static readonly FirstRequestHeader Value = new FirstRequestHeader();
    
        private FirstRequestHeader()
        {
    
        }
    }
    
        2
  •  2
  •   decPL    10 年前

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

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

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

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

        3
  •  2
  •   Uwe Hafner    10 年前

    如果您希望所有实例都具有相同的哈希代码而不使用常量,则也可以使用以下类型的哈希代码:

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