IEquatable <T> - C#中.Equals(object obj)的最佳实践覆盖

ser*_*0ne 4 .net c# boolean equality exception

每当我写一个新的class或者struct可能存有一些数据时,可能需要进行比较,我总是实现,IEquatable<T>因为这提供了class/struct一个强类型的.Equals(T other)方法.

例:

public struct Radius : IEquatable<Radius>
{
    public Int32 TopLeft { get; set; }
    public Int32 TopRight { get; set; }
    public Int32 BottomLeft { get; set; }
    public Int32 BottomRight { get; set; }

    public bool Equals(Radius other)
    {
        return this.TopLeft == other.TopLeft
            && this.TopRight == other.TopRight
            && this.BottomLeft == other.BottomLeft
            && this.BottomRight == other.BottomRight;
    }
}
Run Code Online (Sandbox Code Playgroud)

除了提供实现之外.Equals(Radius other),我还应该覆盖默认实现(.Equals(object obj))

我有两个选择,我的问题是,哪些实现更好?

选项1是使用铸造:

public override bool Equals(object obj)
{
    return this.Equals((Radius)obj);
}
Run Code Online (Sandbox Code Playgroud)

选项2是使用"as"关键字:

public override bool Equals(object obj)
{
    return this.Equals(obj as Radius);
}
Run Code Online (Sandbox Code Playgroud)

我之所以问这个是,利用铸造将抛出一个异常,如果obj不能转换为Radius,而as将解析null,如果它无法施展,所以只检查thisnull未抛出异常; 那么抛出一个异常,还是只返回更好false

编辑:正如很多SO的同事所指出的,结构不能为空,因此第二个选项不适用于结构.因此,另一个问题浮出水面:.Equals(object obj)结构和类的重写实现是否相同?

SLa*_*aks 7

Equals()方法绝不能抛出异常.

不同类型的对象仅仅是不相等的.

引用文档:

Equals的实现不得抛出异常; 他们应该总是返回一个值.例如,如果obj为null,则Equals方法应返回false而不是抛出ArgumentNullException.


Oli*_*ver 5

正如已经提到的@SLaks Equals()绝不应该抛出。

在这种特殊情况下,我认为is结合使用运算符和强制转换应该可以帮助您:

public override bool Equals(object obj)
{
     if(obj is Radius)
         return Equals((Radius)obj);

     return false;
}
Run Code Online (Sandbox Code Playgroud)

如果您有a class,则只需使用as运算符:

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

public bool Equals(MyObj obj)
{
     if(ReferenceEquals(obj, null))
         return false;

     // ToDo: further checks for equality.
}
Run Code Online (Sandbox Code Playgroud)