在类和接口之间进行选择

时间:2012-11-28 17:51:05

标签: c# asp.net asp.net-mvc oop c#-4.0

  

可能重复:
  Interface vs Abstract Class (general OO)

在其中一篇 MSDN 文章中提到以下行

  

接口无法在以后的版本中指定新成员   抽象类可以根据需要添加成员以支持其他成员   功能。

我从 here 中选择了这句话。您可以阅读第3段中的相同句子。

我有一个困惑,提前抱歉,以防我遗失了什么。

一旦声明了Abstaract类或接口,然后任何Derived类继承这些方法,在任何一种情况下,都应该重写所有方法。否则将出现编译错误。

您的意见?

4 个答案:

答案 0 :(得分:4)

  

一旦声明了Abstaract类或接口,然后任何Derived类继承这些方法,在任何一种情况下,都应该重写所有方法。否则将出现编译错误。

不,对于抽象类,只需要覆盖 abstract 方法。您可以添加非抽象方法,没有错误。

例如,版本1:

public abstract class FooBase
{
    public abstract void Bar();    
}

public class FooImpl : FooBase
{
    public override void Bar() {}
}

现在在版本2的FooBase中引入一个新的非抽象方法:

public abstract class FooBase
{
    public abstract void Bar();   

    public void NewMethod() {}
}

......并且没有问题。

请注意,对于公司内部代码,其中所有将要使用API​​的代码同时重建,这通常不是问题,无论是接口还是抽象类。如果要向接口添加方法,可以这样做,因为可以同时升级所有实现。

当你控制整个代码库时,你需要小心。

答案 1 :(得分:1)

实现接口的类必须实现接口中定义的所有方法和属性。

从Abstract类继承时,必须实现/覆盖所有Abstract成员,但是任何非抽象成员都将继承,就像从具体类继承一样。

答案 2 :(得分:0)

实现接口会强制您覆盖其方法 - 继承一个类然后会给您一个选择。只需要覆盖抽象方法。 MSDN摘录指出,当所有实现者都需要实现添加的方法时,严格的接口契约的价格在以后证明是昂贵的。通过使用虚拟方法的父类,您可以稍后决定是否需要专业化。

答案 3 :(得分:0)

从Interfaces继承时,必须实现该接口的所有成员。但您可以根据自己的需要扩展界面。您还可以继承多个接口。有效示例:

public interface IPerson
{
    string FullName { get; set; }
    string SSN { get; set; }
}

public interface IPersonDBContext
{
    void Save(IPerson person);
}

public class PersonData : IPerson, IPersonDBContext
{
    // Implements IPerson FullName
    public string FullName { get; set; }

    // Implements IPerson SSN
    public string SSN { get; set; }

    // Implements IPersonDBContext Save()
    public void Save(IPerson person)
    {
        // Code to save the IPerson instance to the DB...
    }

    // Added method, not included in any interface...
    public void Validate(IPerson person)
    {
        // Code to validate the IPerson instance...
    }
}

现在,对于抽象类,您可以包含可以继承的具体方法,还可以指定一些必须重写的方法。但是,请注意,您不能拥有多个基类(而抽象类仍然是一个类......)因此,您不能像接口那样混合两个抽象类。例如:

public abstract class Person
{
    public string FullName { get; set; }
    public string SSN { get; set; }

    public abstract void Save();
}

public class PersonData : Person
{
    // Implements Abstract Person Save() Method
    public override void Save()
    {
        // Save logic here...
    }

    // Non-inherited member...
    public void Validate()
    {
        // Access properties of the base class (Abstract Person)
        this.FullName.ToString();
        this.SSN.ToString();
    }
}

最后,也是最有力的,你可以将一个抽象基类和你想要的接口混合在一起......所以,如果我保留抽象类Person,来自例2,接口IPersonDBContext来自例1,我可以做到这一点:

public class PersonData : Person, IPersonDBContext
{
    // Implements Abstract Person Save() Method
    public override void Validate()
    {
        // Access properties of the base class (Abstract Person)
        this.FullName.ToString();
        this.SSN.ToString();
    }

    // Inplmenets IPersonDBContext Save()
    public void Save(Person person)
    {
        // Save logic here...
    }

    // Non-inhereted method
    public void Clone(Person person)
    {
        // Logic to make a member-wise clone.
    }
}

希望有帮助...