给出以下接口:
interface IFoo
{
void Foo();
}
interface IBar : IFoo
{
void Bar();
}
表示给定类实现IBar
的最佳方法是什么?
class Implementation : IBar { ... }
这似乎更简单,更清晰,但并不表示Implementation
实施IFoo
。
class Implementation : IBar, IFoo { ... }
这似乎是最有用的,但真正需要额外的信息吗?
答案 0 :(得分:6)
编译器不需要额外的信息,但它可能对您的代码的读者有所帮助,因为读者不必知道IBar
扩展IFoo
。框架中的一个示例是List<T>
,它实现<IList<T>
,ICollection<T>
和IEnumerable<T>
,即使IList<T>
;延伸ICollection<T>
和IEnumerable<T>
。
编辑:我认为,至少对我而言,我列出两者的主要原因是你通常不会想到接口继承彼此。从类派生时,您希望继承本身可以继承的行为。如果您感兴趣,可以按照类层次结构进行推导。使用接口时,接口的派生更加不寻常,因此您不太可能看起来并且更有可能错过连接。列出它们都可以解决这个问题而不会有太多痛苦。
答案 1 :(得分:6)
就个人而言,我会选择前者。对于后者,假设你处于这种情况,你有一堆派生类:
class DerivedA : Implementation, IBar, IFoo { ... }
class DerivedB : Implementation, IBar, IFoo { ... }
class DerivedC : Implementation, IBar, IFoo { ... }
class DerivedD : Implementation, IBar, IFoo { ... }
然后你对Implementation
的要求发生了变化,现在它需要实现另一个接口,例如IBaz
(只要它提供了一个,它就可以做到而不必影响任何派生类。非抽象实现)那么你有两个选择:
保留所有派生类定义,而不显示新接口信息的明确声明,在这种情况下,类定义现在根据标准不正确,如果人们希望始终遵循标准,则可能会产生误导。 / p>
转到并查找所有派生类及其所有派生类,并修复它们的声明。这需要时间,有点容易出错并且难以完全执行,并且将您的单个文件更改为多文件签入。
这两个选项都没有吸引力,所以我选择不会让你陷入困境的选项。只需声明派生最多的界面。
答案 2 :(得分:1)
我会选择A.你可以看看你需要在类中实现哪些方法,IDE中的导航工具将帮助你完成剩下的工作。
在进行任何重构时,B将无法维护(例如,如果您更换IBar或将其拆分为2会发生什么?)答案 3 :(得分:1)
您已经在IFoo
中实现了IBar
这一事实意味着您甚至不需要指定您的具体实现类实现IFoo
; CLR可以推断出这一点,如果您在程序集上使用Reflector,即使使用方法A,它也会指明Implementation
同时实现IFoo
和IBar
。
所以接近它是。
答案 4 :(得分:0)
我认为方法A足够清楚,因为(无论如何在VS.NET中)你可以很快地确定IBar实现了IFoo。
答案 5 :(得分:0)
除了可读性和VB.NET的差异(参见Kathleen Dollard的评论)之外,还存在数据绑定需要(B)的情况。细节已经滑落了我的想法(我会编辑,除非有人打败我...)。
我认为这是.NET Framework集合明确实现其派生接口的原因。
答案 6 :(得分:0)
我会选择方法A,因为在类定义的派生列表中列出一个接口意味着您在该类中提供了一个实现。如果您不打算提供IFoo的替代实现,那么我不会将其包含在列表中,除非您需要它作为简单的“标记接口”。然而,即便如此,在运行时,“is”运算符(返回true或false)或“as”关键字(返回对象或null)将告诉您是否可以将对象强制转换为IFoo。