C#接口实现关系只是“可以做”的关系?

今天有人告诉我,C#中的接口实现只是“Can-Do”关系,而不是“Is-A”关系。 这与我长期相信LSP(Liskov Substitution Principle)相冲突。 我一直认为所有的inheritance应该意味着“Is-A”的关系。

所以,如果接口实现只是一个“可以做”的关系。 如果有一个界面“IHuman”和“IEngineer”,并且一个类“Programmer”inheritance自“IHuman”和“IEngineer”怎么办? 当然,“程序员”是“IHuman”和“IEngineer”。

如果它只是“Can-Do”关系,是否意味着我们不能指望“程序员”实例行为在被视为IHuman并被视为IEngineer时可能会有所不同?

根据我的经验,想到“is-a”和“can-do”关系并没有太大帮助。 你很快就会遇到问题。 它基本上是现实世界和OO之间的阻抗不匹配。 然而,实际上很多人都在谈论对现实世界进行建模,您从根本上需要了解类型之间的关系在您正在使用的平台上意味着什么。

有时接口可以用作function,有时它们可​​以代表更多正常的“is-a”关系。 我不会太在意它 – 只要确保你明白他们能做什么,不能做什么。

我倾向于将接口视为行为契约。 诸如IComparable和IEnumerable之类的接口是经典示例。

在你给出的例子中,IHuman和IEngineer并不是真正的行为。

发现这个问题的时间相当晚,但我想插话。

C#中的接口具有is-a关系,但不是is-an-object。 相反,是实施。

换句话说,对于实现IBar的类Foo,进行以下测试:

Foo myFoo = new Foo(); return myFoo is IBar; 

字面上返回真实。 你也可以说,

 IBar bar = myArrayList[3] as IBar; Foo foo = bar as Foo; 

或者,如果方法需要IBar,则可以传递Foo。

 void DoSomething(IBar bar) { } static void Main() { Foo myFoo = new Foo(); DoSomething(myFoo); } 

显然,IBar本身没有实现,因此can-do关系也适用。

 interface IBar { void happy(); } class Foo : IBar { void happy() { Console.Write("OH MAN I AM SO HAPPY!"); } } class Program { static void Main() { IBar myBar = new Foo(); myBar.happy(); } } 

但是,就此而言,对象inheritance也是如此; inheritance类Bar的类Foo的对象具有can-do关系以及is-a关系,与接口的方式相同。 只是它的实现是为它预先构建的。

真正的问题是,是什么 ,可以做什么 ? inheritance的类对象是-a- [父实例]和can-do- [parent的行为] ,而接口的实现是-a- [接口实现] ,因此可以做[接口行为]

在程序化的大多数情况下 – 使用上面列出的关系,只评估接口,因此inheritance的类和实现的接口共享相同的is-a和can-do质量。

HTH,Jon

.NET框架的设计者使用接口来指定“具有”(或“可以做”)关系,而“是”则使用inheritance来实现。

可以在.NET Framework开发人员指南的“ 选择类和接口之间”部分中找到相应的基本原理:

接口定义实现者必须提供的一组成员的签名。 接口无法为成员提供实现细节。

因此,由于您的“程序员”和“工程师”示例类很可能具有自己的特定function,因此使用inheritance更适合实现它们。

实际上,这就是为什么大多数界面都是function而不是名称,所以你有

IComparable,ITestable,IEnumerable

人类,动物,狗等

无论如何,正如已经提到的那样你必须务实,我在编码时有一个通用的规则: 永远不要让概念,惯例或标准实践在完成工作的过程中得到改进,比学术更好务实。

所以,如果你确定界面真的更适合你的设计,那就去吧,不要担心这个问题。