C# 抽象类优于接口

C# 抽象类优于接口,c#,C#,我从你那里得到以下声明。它说抽象类比接口有优势,因为可以修改抽象类来添加新成员。改变抽象类真的会使从抽象类继承的类不稳定吗?或者有人能解释一下他们的观点吗 不要偏向于定义类而不是接口 在库的更高版本中,您可以安全地将新成员添加到 班级;在不中断的情况下,无法将成员添加到接口 现行守则 抽象类的最大优点是可以拥有内部成员,而接口不能拥有内部成员。另一方面,您可以在接口上拥有多重继承,但在摘要类上则没有 抽象类的优点是可以实现通用功能。有了接口,每个实现类都必须提供自己定义的操作的实现。假设您编写代

我从你那里得到以下声明。它说抽象类比接口有优势,因为可以修改抽象类来添加新成员。改变抽象类真的会使从抽象类继承的类不稳定吗?或者有人能解释一下他们的观点吗

不要偏向于定义类而不是接口

在库的更高版本中,您可以安全地将新成员添加到 班级;在不中断的情况下,无法将成员添加到接口 现行守则


抽象
类的最大优点是可以拥有内部成员,而
接口
不能拥有内部成员。另一方面,您可以在
接口
上拥有多重继承,但在
摘要
类上则没有

抽象类的优点是可以实现通用功能。有了接口,每个实现类都必须提供自己定义的操作的实现。

假设您编写代码并在第一个版本中使用一些接口(
IExample
)。在程序的第二个版本中,您知道
IExample
应该有一个名为
IExample.NewMethod
的方法。如果使用此方法扩展
IExample
,您以前编写的所有代码将自动中断,因为从
IExample
继承的所有类都不会完全实现此接口,因此不会编译代码。如果我们只讨论这个案子是正确的。这个问题可以通过使用从
IExample
继承的新接口(
INewExample
)来解决,或者只创建没有继承的新接口

但接口对于抽象类也有一些优势。接口比抽象类更好地封装了代码的实现。您也可以为不同的类使用接口,但当您使用抽象类时,这意味着您的类在某种程度上是抽象类(例如,
Circle
是一个
Shape
,因此您可以从abstract
Shape
继承
Circle
)但是从
Car
继承
Circle
确实是个坏主意,即使它们有相同的接口


要阅读接口与抽象类的完整概述,我建议您编写完整的继承代码。通过接口(作为契约)编程确实是解耦应用程序的最佳方式。例如,围绕接口创建包装器非常容易,而类甚至不必有单个虚拟方法

此外,它甚至没有将
抽象
类与接口进行比较(因为它只在下一个“指南”中提到它们),而是将所有类一般都与接口进行比较。所以,如果你问我的话,这是一个相当模糊的指导方针

这可能只适用于所述的问题:更改接口会破坏所有实现,而向类添加成员则不会。另一方面,如果您更改了一个方法的签名,那么使用类也不会很幸运。从安全性的角度来看,抽象类确实提供了一种方法来确保您的库始终向调用者公开自己的功能,只允许在需要的地方进行修改。使用接口,您可以传递几乎任何满足契约的代码

改变抽象类真的会使从抽象类继承的类不稳定吗

不一定。只要不将新成员标记为
virtual
,当前不使用新成员的任何类都可以忽略它们,因此没有版本控制中断

或者有人能解释一下他们的观点吗


关键是,如果向接口添加新成员,任何实现该接口的类都会立即中断,因为它没有实现新成员。在向抽象类添加成员时,没有这种构建中断。

假设您有一个接口

public interface Animal 
{
     void Sleep();
}
public abstract class Animal 
{
    public abstract  void Sleep();
} 
释放库后,您发现需要向接口添加属性

public interface Animal 
{
     int Age{get;set;}
     void Sleep();
}
每个人针对接口的第一个版本编写的所有代码将不再编译并强制升级。如果您发布了带有此抽象类的第一个版本

public abstract class Animal 
{
    public abstract  void Sleep();
} 
现在需要添加另一个属性

public abstract class Animal
{
    public virtual int Age{get;set;}
    public abstract  void Sleep();
} 

在这种情况下,用户无需更改这些代码

如果向接口添加成员,则实现旧接口的任何类都不会包含新成员,因此将不再编译。虽然如果将抽象成员添加到抽象类中也是如此。您当然是指
抽象
,而不是
虚拟
。我实际上是指两者(并且
抽象
成员总是
虚拟
,因此
虚拟
涵盖了这两种情况)。考虑类<代码> Base<代码>属性>代码> A <代码> >代码> b>代码>和<代码> c>代码>。如果一个类
Derived:Base
包含成员
D
,然后
Base
添加
virtual
成员
D
,那么
Derived
现在编译时会出现警告,就像在中的
Meth3
示例中一样。好的,您是指出现名称冲突的情况。@OlivierJacot Descombes,因为如果您允许其他人对您的抽象类进行子类化,您就无法控制他们使用哪些名称作为其成员。感谢您的回答,我们可以将方法更改为与您显示的属性类似的方法吗。。。。我对接口有点困惑:(你可以添加一个新的方法,如果不强制所有下游消费者进行更改,你不能更改一个方法严格来说,你所指的不是真正的“多重继承”-即使使用接口,也不是从多个基类继承-只是实现了多个接口。虽然很轻微,但很重要