简体   繁体   English

实体类的GetHashCode()的正确实现是什么?

[英]What is the correct implementation for GetHashCode() for entity classes?

Below is a sample implementation of overriding Object.Equals() for an entity base class from which all other entities in an application derive. 下面是一个覆盖实体基类的Object.Equals()的示例实现,应用程序中的所有其他实体都从该实体基类派生。

All entity classes have the property Id, which is a nullable int. 所有实体类都具有属性Id,它是一个可以为null的int。 (It's the primary key of whatever table the entity class corresponds to.) (它是实体类对应的任何表的主键。)

public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;

            if (base.Equals(obj))
                return true;

            return Id.HasValue && ((EntityBase) obj).Id.HasValue &&
                   Id.Value == ((EntityBase) obj).Id.Value;
        }

Given this implementation of Equals(), how do you correctly implement GetHashCode()? 鉴于Equals()的这种实现,你如何正确实现GetHashCode()?

If you're deriving from something that already overrides GetHashCode I'd implement it as: 如果您从已经覆盖GetHashCode内容派生,我将其实现为:

public override int GetHashCode()
{
    unchecked
    {
        int hash = 37;
        hash = hash * 23 + base.GetHashCode();
        hash = hash * 23 + Id.GetHashCode();
        return hash;
    }
}

A null value of Id will return 0 for Id.GetHashCode(). 对于Id.GetHashCode(),Id的空值将返回0。

If your class just derives from Object, I'd just return Id.GetHashCode() - you do not want to include the object.GetHashCode implementation in your hash code, as that basically ends up being object identity. 如果您的类只是从Object派生,我刚刚返回Id.GetHashCode() -你希望包括object.GetHashCode在你的哈希码实现,因为这基本上结束是对象的身份。

Note that your equality definition won't return true if neither entity has an Id, but the same hashcode will be returned from both objects. 请注意,如果两个实体都没有Id,则您的相等定义将不会返回true ,但是将从两个对象返回相同的哈希码。 You may wish to consider changing your Equals implementation. 您可能希望考虑更改您的Equals实施。

What Jon Skeet answered is a good solution, however, you might want to add an unchecked code block to allow integer overflowing Jon Skeet回答的是一个很好的解决方案,但是,您可能希望添加一个未经检查的代码块以允许整数溢出

unchecked
{
  int hash = ...;
  return hash
}

https://msdn.microsoft.com/en-us/library/khy08726(v=vs.140).aspx https://msdn.microsoft.com/en-us/library/khy08726(v=vs.140).aspx

If neither checked nor unchecked is specified, the default context depends on external factors such as compiler options. 如果既未指定也未取消选中,则默认上下文取决于外部因素,例如编译器选项。

I'd also like to add, again, that using base.GetHashCode() on POCO's will call the default object.GetHashCode . 我还想再次补充说,在POCO上使用base.GetHashCode()会调用默认的object.GetHashCode That's definitely not what you want... 这绝对不是你想要的......

What about using the type as part of the hash code? 将类型用作哈希码的一部分怎么样?
Would this be a good implementation? 这是一个很好的实施吗?

public class Foo
{
    public int Id { get; set; }

    // other properties here
    // ......

    public override int GetHashCode()
    {
        int hash = 37;
        hash = hash * 23 + typeof(Foo).GetHashCode();
        hash = hash * 23 + Id.GetHashCode();
        return hash;
    }
}

You can only correctly implement GetHashCode() if the Id property is immutable for the lifetime of an instance (or at least for the time that its hash needs to be used, such as while the object is in a map or other collection requiring the hash). 如果Id属性在实例的生命周期中是不可变的(或者至少在其哈希需要使用的时间,例如当对象在地图或其他需要哈希的集合中时GetHashCode()则只能正确实现GetHashCode() )。

Assuming that it is, you can just use the value of Id as the hash for all valid values and then use a fixed hash for null. 假设它是,您可以使用Id的值作为所有有效值的哈希值,然后使用固定哈希值为null。 I can't remember what the most appropriate is for this, but I would assume a randomly selected value for null(randomly selected prior to compilation, not at runtime) or the median value of valid Id values (ie halfway between 0 and int.Max). 我不记得最合适的是什么,但我会假设一个随机选择的null值(在编译之前随机选择,而不是在运行时)或有效Id值的中间值(即在0和int之间的中间值)。最大)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM