C# C"接口实现关系只是";能行;关系

C# C"接口实现关系只是";能行;关系,c#,inheritance,interface,liskov-substitution-principle,C#,Inheritance,Interface,Liskov Substitution Principle,今天有人告诉我,C#中的接口实现只是“可以做”的关系,而不是“is-A”关系。这与我长期以来对LSP(利斯科夫替代原则)的信仰相冲突。我一直认为所有的继承都应该意味着“是一种”关系 所以,如果接口实现只是一种“可以做”的关系。如果有一个接口“IHuman”和“IEngineer”,并且有一个类“Programmer”继承自“IHuman”和“IEngineer”,该怎么办?当然,“程序员”是“IHuman”和“IEngineer” 如果只是“可以做”的关系,这是否意味着我们不能期望“程序员”实例

今天有人告诉我,C#中的接口实现只是“可以做”的关系,而不是“is-A”关系。这与我长期以来对LSP(利斯科夫替代原则)的信仰相冲突。我一直认为所有的继承都应该意味着“是一种”关系

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


如果只是“可以做”的关系,这是否意味着我们不能期望“程序员”实例的行为在被视为IHuman和IEngineer时可能有所不同?

我倾向于将接口视为行为契约。IComparable和IEnumerable等接口就是典型的例子


在您给出的示例中,IHuman和IEngineer并不是真正的行为

根据我的经验,考虑“是一个”和“可以做”的关系并没有多大帮助。你很快就会遇到问题。基本上,这是现实世界和OO之间的阻抗不匹配。无论人们实际上谈论如何对现实世界建模,您基本上都需要理解类型之间的关系在您使用的平台上意味着什么


有时接口可以用作功能,有时它们更能代表正常的“is-a”关系。我不会对此挂断电话——只要确保您了解他们能做什么和不能做什么。

NET framework的设计者使用接口来指定“has a”(或“can do”)关系,而“is a”是使用继承实现的

这方面的基本原理可以在.NET Framework开发者指南的一节中找到:

接口定义了实现者必须提供的一组成员的签名。接口无法提供成员的实现详细信息


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

实际上,这就是为什么大多数接口都是功能而不是名称的原因

i可比较,it稳定,i可计算

人、动物、狗等

无论如何,正如前面提到的,您必须务实,我在编写代码时有一条一般规则:永远不要让概念、惯例或标准实践妨碍完成工作,最好务实而不是学术。


所以,如果你确信界面确实更适合你的设计,那就去做吧,不要担心像这样的问题。

很晚才发现这个问题,但我想插话

C#中的接口具有is-a关系,但不是对象。相反,这是一种实现

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

Foo myFoo = new Foo(); 
return myFoo is IBar;
字面上返回true。你也可以说,

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();
    }
}
但是,就这一点而言,对象继承也是如此;继承类Bar的类Foo的对象具有can-do关系以及is-a关系,其方式与接口相同。只是它的实现是为它预先构建的

真正的问题是,你能做什么?继承的类对象是一个-[parent instance],可以执行-[parent's behavior],而接口的实现是一个-[interface implementation],因此可以执行-[interface behavior]

在大多数使用编程is-a关系的情况下(如上面列出的),只对接口进行求值,因此继承的类和实现的接口共享相同的is-a和can-do质量

嗯,,
乔恩:很高兴你喜欢。完成后一定要给我反馈:)如果你有一个只包含抽象方法的抽象类怎么办?这与界面有什么不同?我相信只要有方法就没有区别。那为什么微软带来了两件事呢。继承是有is-a关系的,什么接口实现?@Sudhir.net:我尽量避免谈论“is-a”关系等,正如我在第一句中指出的那样。只有抽象方法的抽象类与接口在许多细节上不同,例如一个类只能从另一个类派生,但能够实现多个接口。类不能声明泛型差异,并且总是值类型(而接口也可以通过值类型实现)。抽象类更容易进化,因为可以添加新的(非抽象)方法,而不破坏现有的子类。@Jon,我的抽象类在整个应用程序周期中只有一个abtract。将来abtract类没有变化,例如没有多个接口,没有字段,没有非abtract方法。那我的界面有什么不同呢。?我想从实现的角度来理解,微软的想法是什么?@Sudhir.net:这并不是说C#是第一个进行这种拆分的语言——首先,它与Java中的抽象类和接口非常相似。问题不在于抽象类实现了多个接口,而是如果您有第二个抽象类,则单个类无法从这两个抽象类派生,但它可以实现多个接口。真的,所以评论并不是讨论这些差异的最佳场所——我建议你找一本好的入门C#书。