2014-02-28 59 views
3

等于I有一个类实现接口,诸如这样的:重写在C#接口实现

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; 
} 
+7

2个样本实现完全不同的功能 - 由您来决定你需要什么。一个相同的类型+相同的属性,花药 - 实现相同的接口+相同的属性。如果你希望'AClass'的实例等于其他类的类似对象(如[duck typing](http://en.wikipedia.org/wiki/Duck_typing)),则使用第二个类,第一个接近标准值“Equals”类型的行为 –

回答

6

可以做无论你想要的。两者在功能上并不相同,但对您而言“正确”是我们无法回答的。如果我有一个BClass类实现相同的接口,并且它具有相同的值为这两个属性,应该它等于您的AClass对象?如果是的话,做后者,如果没有,做前者。

就我个人而言,我会找到后者。一般来说,我发现如果一个班级要实施自己对平等的个人定义,其他班级就不应该等于它。其中一个主要原因是,如果平等是对称的,那么最好。也就是说aclass.Equals(bclass)应该返回与bclass.Equals(aclass)相同的结果。如果不将平等限制为相同类型,那么获得这种行为是很困难的。它需要所有相关类的合作。

如果你有一些令人信服的理由是比较IInterface实施中,他们可能是不同的底层阶级,但仍然都为“平等”,我个人更喜欢创造IEqualityComparer<IInterface>定义平等该接口。这将与两个实施类别中的任何一个的平等定义分开。

+0

缺乏对称性是唠叨我的东西,但我无法完全表达它。 – Dave

2

决定如何需要它的功能。

ReSharper的实现:

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; } 
} 
0

如果接口的目的是从消费者隐瞒事实,两个等价的对象可能是不同类的,它可能是一个好主意,定义其保持接口类型和链的单一私有字段一个struct接口的适当方法。使用这样的结构通常应该与使用接口类型的变量(主要的例外是如果结构最终被装箱)一样高效,但是会阻止客户端代码看到实现接口的实际类型。

例如,一个可能有一个接口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>一个实例,它拥有一个12×12阵列发生在比对角线上的其他每一个元件可以保持零,而其他可能是DiagonalMatrix<double>,并使用12项数组,仅仅保存在对角线上的东西(并且响应于对任何其他元素的请求而返回零)。使用不同类型来存储数组数据应该是一个实现细节,并且不会暴露给客户端。

使用结构来包装数组的一个细节是默认值结构的引用类型字段为空,但结构本身不会。因此可能希望结构实现IsNull属性,如果后台字段为null则返回true,否则让其他结构成员检查后备字段是否为空,如果是,则表现为空的0x0矩阵。