8

C# 8及更高版本中,我们有默认的接口方法,因此:

它不会破坏接口的原理吗?

我们什么时候应该使用默认接口方法而不是基(抽象)类

4

2 回答 2

9

为什么我们有接口?

从理论上讲,接口实现和类继承都解决了同一个问题:它们允许您定义类型之间的子类型关系

那么为什么我们在 C# 中两者都有呢?为什么我们需要接口?我们不能像在 C++ 中那样将接口定义为抽象类吗?

原因是钻石问题:(图片来源

在此处输入图像描述

如果两者都B实现C不同A.DoSomething(),应该D继承哪个实现?这是一个难题,Java 和 C# 设计者决定通过只允许不包含任何实现的特殊基类型的多重继承来避免它。他们决定将这些特殊的基本类型称为接口

所以,没有“接口原则”。接口只是解决特定问题的“工具”。

那么为什么我们需要默认实现呢?

向后兼容性。您编写了一个非常成功的库,全世界成千上万的开发人员都在使用它。您的库包含一些 interface I,现在您决定需要一个额外的方法M。问题是:

  • 您不能向 中添加其他方法MI因为这会破坏现有类的实现I(因为它们没有实现M),并且
  • 您不能更改I为抽象基类,因为这也会破坏现有的实现类I,并且您将失去进行多重继承的能力。

那么默认实现如何避免菱形问题呢?

通过不继承这些默认方法(受本文启发的示例,请参阅完整文章了解一些有趣的极端案例):

interface I1
{
    void M() { Console.WriteLine("I1.M"); } // default method
}

interface I2
{
    void M() { Console.WriteLine("I2.M"); } // default method
}

class C : I1, I2 { }

class Program
{
    static void Main(string[] args)
    {
        // c, i1 and i2 reference the same object
        C c = new C();
        I1 i1 = c;
        I2 i2 = c;

        i1.M(); // prints "I1.M"
        i2.M(); // prints "I2.M"
        c.M();  // compile error: class 'C' does not contain a member 'M'
    }
}
于 2020-07-10T11:49:35.413 回答
1

正如文档中所解释的,有两个主要应用程序:

扩展现有 API

虚拟扩展方法使 API 作者能够在未来版本中向接口添加方法,而不会破坏与该接口现有实现的源代码或二进制兼容性。

因此,它旨在作为一种扩展 API(= 一组接口)的方法,而无需更新所有现有的实现(因为它们需要实现新添加的功能)。

特征模式

特征模式允许使用多组预先实现的方法来扩展一个类。这对于抽象类是不可能的:给定的类只能从单个父类继承,但可以从多个接口继承。

请注意,此功能带有菱形继承问题。因此,除了这些特定的应用程序之外,不应使用此功能来替换抽象类。

于 2020-07-10T11:21:31.323 回答