C# 当对象';s的标识符为空?

C# 当对象';s的标识符为空?,c#,gethashcode,iequatable,C#,Gethashcode,Iequatable,考虑到identity属性可能为null,以下哪项正确/更好 public override int GetHashCode() { if (ID == null) { return base.GetHashCode(); } return ID.GetHashCode(); } 或 更新1:更新了第二个选项 更新2:以下是Equals实现: public bool Equals(IContract other) { if (other == n

考虑到identity属性可能为null,以下哪项正确/更好

public override int GetHashCode()
{
    if (ID == null) {
        return base.GetHashCode();
    }
    return ID.GetHashCode();
}

更新1:更新了第二个选项

更新2:以下是Equals实现:

public bool Equals(IContract other)
{
    if (other == null)
        return false;
    if (this.ID.Equals(other.ID)) {
        return true;
    }
    return false;
}

public override bool Equals(object obj)
{
    if (obj == null)
        return base.Equals(obj);
    if (!obj is IContract) {
        throw new InvalidCastException("The 'obj' argument is not an IContract object.");
    } else {
        return Equals((IContract)obj);
    }
}

ID是
string
类型。

它实际上取决于您希望相等的含义-重要的是两个相等的对象返回相同的hashcode。当ID为空时,相等意味着什么?当前,如果ID属性具有相同的值,那么Equals方法必须返回true。。。但我们不知道ID为null时会发生什么

如果你真的想要第一个版本的行为,我个人会使用:

return ID == null ? base.GetHashCode() : ID.GetHashCode();
编辑:基于Equals方法,看起来您可以使GetHashCode方法:

return ID == null ? 0 : ID.GetHashCode();
请注意,您的
Equals(IContract other)
方法也可以如下所示:

return other != null && object.Equals(this.ID, other.ID);
如果
this.ID
为空,则当前实现实际上会引发异常

此外,您的
Equals(object)
方法不正确-如果传递了不适当的对象类型,您不应该抛出异常,您应该返回
false
。。。如果
obj
为空,则同上。因此,您实际上可以使用:

public override bool Equals(object obj)
{
    return Equals(obj as IContract);
}

然而,我关心的是基于接口的平等性。通常,两个不同类型的类不应该被认为是相等的,即使它们实现了相同的接口。

也许您想要的是这样的

override int GetHashCode()
{
    if (ID != null)
        return ID.GetHashCode();

    return DBNull.Value.GetHashCode();
}

重要的是,两个具有空ID的对象是否应该被视为相等?

您可以简单地
返回0
,您需要为相同的值返回相同的HashCode,并且ID.GetHashCode()通常不会返回0,因此这种Hash函数可以满足任何需要。由于您没有组合任何值(如ID和Name散列),因此它非常清晰的ID是HashCode的定义源,因此将空ID的0固定为合理

否则,您在GetHashCode覆盖中仅考虑ID字段的整个方法可能是错误的(并且您需要组合几个字段以从中计算哈希)

在您的编辑之后,我可以说second Equals override有太多代码,只需将其替换为

public override bool Equals(object obj)
{
    return Equals(obj as Contract);
}
您的Equals(IContract合约)覆盖在我看来似乎有问题,因为定义合约的唯一东西是ID,如果IContract的字段数大于ID,那么它将是一个糟糕的Equals覆盖


PS:实际上,如果IContract是一个接口,您可能需要将您的
IEquatable
替换为一个具体的
IEquatable
契约,因为能够返回实现同一接口的不同类实例相等的设计将是不好的,因为根据定义相等需要检查对象是否具有平等性检查第一阶段的相同类型(通常在99.9%的情况下)

接口的平等性应放在自己的类中,实现
IEqualityComparer
,然后使用该类通过调用@Oliver:Agreed实例化词典,如果确实需要的话。。。但我不记得上次我想用一个通用接口比较两种不同类型的对象是什么时候了。@Jon:谢谢你的回答,这总是一个C课程。:)采用基于接口的平等的原因是,我的应用程序的设计方式是,接口与类(实体)之间有一对一的映射,此外,在整个应用程序中,Contract类型的对象被用作IContract,因此我必须在另一种情况下在每个位置将其强制转换为Contract,以检查是否相等。@Dienekes:嗯,您的Equals(object)方法可以解决这个问题。如果您的意思是只与其他合同类进行同等比较,那么就这样做吧。如果您真的希望IContract实现平等,我建议您创建一个
IEqualityComparer
。^^^谢谢。顺便说一句,我的应用程序是这样设计的:接口与类(实体)有一对一的映射,这就是为什么我在接口而不是类中继承了IEquatable。此外,在整个应用程序中,Contract类型的对象被用作IContract,因此我必须在另一种情况下在每个位置将其强制转换为Contract,以检查是否相等。
public override bool Equals(object obj)
{
    return Equals(obj as Contract);
}