3

我有一个实现接口的类,例如:

interface IInterface
{
   string PropA { get; }
   string PropB { get; }
}

class AClass : IInterface
{
   string PropA { get; protected set; }
   string PropB { get; protected set; }
}

平等是根据 PropA 和 PropB 确定的。当覆盖 AClass 的 Equals 方法时,我是否应该尝试将 obj 转换为 AClass,如下所示:

public override bool Equals(object obj)
{
   AClass other = obj as AClass;
   return other != null 
       && AClass.PropA == other.PropA 
       && AClass.PropB == PropB;
}

或者我应该尝试将 obj 转换为 IInterface,如下所示:

public override bool Equals(object obj)
{
   IInterface other = obj as IInterface;
   return other != null 
       && AClass.PropA == other.PropA 
       && AClass.PropB == PropB;
}
4

3 回答 3

7

可以做任何你想做的事。两者在功能上是不一样的,但对你来说“正确”是我们无法回答的。如果我有一个BClass实现相同接口的类,并且它的两个属性具有相同的值,它是否应该等于您的AClass对象?如果是,做后者,如果不是,做前者。

就个人而言,我会发现后者有关。一般来说,我发现如果一个类要实现自己的平等定义,其他类不应该与它相等。一个主要原因是,如果相等是对称的,则更可取。也就是说aclass.Equals(bclass)应该返回与bclass.Equals(aclass). 当您不将相等性限制为同一类型时,获得这种行为是......很难。它需要所有相关类的合作。

如果您有一些令人信服的理由来比较IInterface它们可能是不同的底层类但仍然“相等”的实现,我个人更喜欢创建一个为该接口IEqualityComparer<IInterface>定义相等的实现。这将与两个实现类中的任何一个的相等定义分开。

于 2014-02-28T17:39:20.807 回答
2

决定你需要它如何运作。

更清晰的实现:

class AClass : IInterface, IEquatable<AClass>
{
    public bool Equals(AClass other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return string.Equals(this.PropA, other.PropA) && string.Equals(this.PropB, other.PropB);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (AClass)) return false;
        return Equals((AClass)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ((this.PropA != null ? this.PropA.GetHashCode() : 0) * 397) ^ (this.PropB != null ? this.PropB.GetHashCode() : 0);
        }
    }

    public string PropA { get; protected set; }
    public string PropB { get; protected set; }
}
于 2014-02-28T17:34:32.873 回答
0

如果接口的目的是向消费者隐藏两个等效对象可能属于不同类的事实,那么定义一个结构可能是一个好主意,该结构包含该接口类型的单个私有字段并链接到相应的方法接口。使用这样的结构通常应该与使用接口类型的变量一样有效(主要的例外是结构最终被装箱),但会屏蔽客户端代码查看实现接口的实际类型。

例如,可能有一个接口IReadableMatrix<T>IImmutableMatrix<T>,以及相应的结构ReadableMatrix<T>,并ImmutableMatrix<T>具有只读成员int Heightint Width、 和T this[int row, int column]、 和ImmutableMatrix<T> AsImmutable();。使用不ImmutableMatrix<double>应该关心它的存储方式的代码;完全有可能两个实例ImmutableMatrix可能持有对不同实现的引用,这些实现IImmutableMatrix<T>在每个单元格中报告相同的内容,但存储的东西完全不同。一个可能是 的一个实例ArrayBackedMatrix<double>,它包含一个 12x12 数组,该数组恰好在除对角线上的元素之外的每个元素中都包含零,而另一个可能是DiagonalMatrix<double>, 并使用 12 项数组,该数组仅存储对角线上的内容(并返回零以响应对任何其他元素的请求)。使用不同的类型来存储数组数据应该是一个实现细节,而不是暴露给客户端。

使用结构包装数组的一个小细节是默认值结构的引用类型字段将为空,但结构本身不会。因此,可能需要让结构实现一个属性,如果支持字段为,则IsNull返回该属性,或者让其他结构成员检查支持字段是否为空,如果是,则表现为空的 0x0 矩阵。truenull

于 2014-02-28T20:40:19.143 回答