简体   繁体   English

为ValueObject实现GetHashCode和Equals方法的实现

[英]Implemeting GetHashCode and Equals methods for ValueObjects

There is a passage from NHibernate documentation: NHibernate文档中有一段内容:

Note: if you define an ISet of composite elements, it is very important to implement Equals() and GetHashCode() correctly. 注意:如果定义复合元素的ISet ,正确实现Equals()GetHashCode()非常重要。

What does correctly mean there? 那里的correctly含义是什么? Is it neccessary to implement those methods for all value objects in domain? 是否需要为域中的所有值对象实现这些方法?

EXTENDING MY QUESTION 扩展我的问题

In the article Marc attached user Albic states: 在文章马克连接用户白浆指出:

It's actually very hard to implement GetHashCode() correctly because, in addition to the rules Marc already mentioned, the hash code should not change during the lifetime of an object. 正确实现GetHashCode()实际上非常困难,因为除了已经提到的Marc规则外,哈希码在对象的生存期内不应更改。 Therefore the fields which are used to calculate the hash code must be immutable. 因此,用于计算哈希码的字段必须是不可变的。

I finally found a solution to this problem when I was working with NHibernate . 当我与NHibernate合作时,我终于找到了解决该问题的方法。 My approach is to calculate the hash code from the ID of the object. 我的方法是根据对象的ID计算哈希码。 The ID can only be set though the constructor so if you want to change the ID, which is very unlikely, you have to create a new object which has a new ID and therefore a new hash code. 只能通过构造函数来设置ID,因此,如果您想更改ID(这是不太可能的),则必须创建一个具有新ID和新哈希码的新对象。 This approach works best with GUIDs because you can provide a parameterless constructor which randomly generates an ID. 这种方法最适合GUID,因为您可以提供一个无参数的构造函数,该构造函数会随机生成一个ID。

I suddenly realized what I've got inside my AbstractEntity class: 我突然意识到我在AbstractEntity类中获得了什么:

public abstract class AbstractEntity<T> where T : AbstractEntity<T> {
    private Nullable<Int32> hashCode;

    public virtual Guid Id { get; protected set; }
    public virtual Byte[] Version { get; set; }

    public override Boolean Equals(Object obj) {
        var other = obj as T;
        if(other == null) {
            return false;
        }

        var thisIsNew = Equals(this.Id, Guid.Empty);
        var otherIsNew = Equals(other.Id, Guid.Empty);

        if(thisIsNew && otherIsNew) {
            return ReferenceEquals(this, other);
        }

        return this.Id.Equals(other.Id);
    } // public override Boolean Equals(Object obj) {

    public override Int32 GetHashCode() {
        if(this.hashCode.HasValue) {
            return this.hashCode.Value;
        }

        var thisIsNew = Equals(this.Id, Guid.Empty);
        if(thisIsNew) {
            this.hashCode = base.GetHashCode();
            return this.hashCode.Value;
        }
        return this.Id.GetHashCode();
    } // public override Int32 GetHashCode() {

    public static Boolean operator ==(AbstractEntity<T> l, AbstractEntity<T> r) {
        return Equals(l, r);
    }
    public static Boolean operator !=(AbstractEntity<T> l, AbstractEntity<T> r) {
        return !Equals(l, r);
    }
} // public abstract class AbstractEntity<T>...

As all components are nested within entities should I then implement Equals() and GetHashCode() for them? 由于所有components都嵌套在entities因此我应该为它们实现Equals()GetHashCode()吗?

Correctly means that GetHashCode returns the same hash code for the entities that are expected to be equal. 正确地意味着, GetHashCode预期相等的实体返回相同的哈希码。 Because equality of 2 entities is made by comparison of that code. 因为2个实体的相等性是通过比较该代码来实现的。

On the other side, that means that for entities that are not equal, the uniqueness of hash code has to be guaranteed , as much as it possible. 另一方面,这意味着对于不相等的实体,必须尽可能保证哈希码的唯一性。

The documentation for Equals and GetHashCode explain this well and include specific guidance on implementation for value objects. EqualsGetHashCode的文档对此进行了很好的解释,并包括有关实现值对象的特定指南。 For value objects, Equals is true if the objects are the same type and the public and private fields are equal. 对于值对象,如果对象是相同类型并且公共字段和私有字段相等,则Equals为true。 However, this explanation applies to framework value types and you are free to create your own Equals by overriding it. 但是,此说明适用于框架值类型,您可以通过覆盖它来自由创建自己的Equals。

GetHashCode has two rules that must be followed: GetHashCode有两个必须遵循的规则:

  • If two objects compare as equal, the GetHashCode method for each object must return the same value. 如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值。 However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values. 但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值。

  • The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. 只要没有修改确定对象的Equals方法返回值的对象状态,对象的GetHashCode方法就必须始终返回相同的哈希码。 Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again. 请注意,这仅适用于当前执行的应用程序,并且如果再次运行该应用程序,则可以返回不同的哈希码。

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

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