【问题标题】:Default Interface Methods. What is deep meaningful difference now, between abstract class and interface? [closed]默认接口方法。现在,抽象类和接口之间有什么深刻的有意义的区别? [关闭]
【发布时间】:2017-12-01 21:00:22
【问题描述】:

我知道抽象类是一种不能被实例化的特殊类。抽象类只能被子类化(继承自)。换句话说,它只允许其他类从它继承,但它不能被实例化。优点是它可以为所有子类强制执行某些层次结构。简单来说,它是一种强制所有子类继承相同层次结构或标准的契约。

我也知道接口不是类。它是由“接口”一词定义的实体。接口没有实现;它只有签名,或者换句话说,只有没有主体的方法的定义。作为与抽象类的相似之处之一,它是一种契约,用于定义所有子类的层次结构,或者它定义了一组特定的方法及其参数。它们之间的主要区别在于,一个类可以实现多个接口,但只能从一个抽象类继承。由于 C# 不支持多重继承,因此使用接口来实现多重继承。

当我们创建一个接口时,我们基本上是在创建一组没有任何实现的方法,这些实现必须被实现的类覆盖。优点是它提供了一种方法让一个类成为两个类的一部分:一个来自继承层次结构,一个来自接口。

当我们创建一个抽象类时,我们正在创建一个基类,它可能具有一个或多个已完成的方法,但至少有一个或多个方法未完成并声明为抽象类。如果一个抽象类的所有方法都不完整,那么它就是一个接口。

但是 但是 但是

我注意到我们将在 C# 8.0 中使用默认接口方法

也许我问它是因为我只有 1-2 年的编程经验,但是 现在抽象类和接口之间的主要区别是什么?

我知道我们不能在界面中做状态,它们之间会不会只有一个区别?

【问题讨论】:

  • 诚实吗?它们将变得几乎相同,同时将模拟多重继承引入 C#。这是许多 C# 开发人员(包括我自己)完全反对该功能的主要原因之一。
  • 我最近评论说,C#6 旨在展示编程语言设计中的收益递减,而 C#7 旨在展示收益递减的收益递减。您可以看到 C#8 的发展方向。它正在形成一种四维雪球。微软需要为这些人找到一种新的工作语言。这个完成了。它具有所有功能。
  • 其实我真的很喜欢不可为空引用类型的想法。
  • @EdPlunkett 哈!在完成您之前的评论时,我在想正是。可能是因为我今天早上刚读到一篇关于他们的文章。
  • 我同意默认接口方法会增加混乱,除非因此用作我们应该为其引入命名约定的特征(例如 IFooTrait 或只是 FooTrait)。

标签: c# interface abstract-class c#-8.0 default-interface-member


【解决方案1】:

除了抽象类可以具有状态而接口不能具有明显的事实之外,两者之间没有很多区别。默认方法或也称为虚拟扩展方法实际上已经在 J​​ava 中可用了一段时间。默认方法的主要驱动力是接口演变,这意味着能够在未来版本中向接口添加方法,而不会破坏与该接口现有实现的源代码或二进制兼容性。

post 提到的另外几个优点:

【讨论】:

  • w.r.t.Java IMO Java 有默认方法的原因,一个劣质的构造,是因为他们无法接受复制更好的 C# 扩展方法。现在 C# 无缘无故地从 Java 复制了默认方法,而不是提供特征的真正实现(具有状态)。
【解决方案2】:

概念

首先,类和接口之间存在概念上的区别。

  • 一个类应该描述一个“是一个”关系。例如。法拉利就是汽车
  • 一个接口应该描述一个类型的契约。例如。汽车有方向盘。

目前抽象类有时用于代码重用,即使没有“是”关系。这污染了OO设计。例如。 FerrariClass 继承自 CarWithSteeringWheel

好处

  • 因此,从上面来看,您可以在不引入(概念上错误的)抽象类的情况下重用代码。
  • 你可以从多个接口继承,而抽象类只是单继承
  • 接口存在协变和逆变,C# 中的类不存在
  • 实现接口更容易,因为某些方法具有默认实现。这可以为接口的实现者节省大量工作,但用户不会看到区别:)
  • 但对我来说最重要的是(因为我是库维护者),您可以在不进行重大更改的情况下向接口添加新方法!在 C# 8 之前,如果一个接口被公开发布,它应该被修复。因为更改界面可能会破坏很多。

记录器界面

这个例子展示了一些好处。

您可以如下描述(过于简单的)记录器接口:

interface ILogger
{
    void LogWarning(string message);

    void LogError(string message);

    void Log(LogLevel level, string message);
}

然后,该界面的用户可以使用LogWarningLogError 轻松记录警告和错误。但缺点是实现者必须实现所有方法。

一个更好的默认界面是:

interface ILogger
{
    void LogWarning(string message) => Log(LogLevel.Warning, message);

    void LogError(string message) => Log(LogLevel.Error, message);

    void Log(LogLevel level, string message);
}

现在用户仍然可以使用所有方法,但实现者只需要实现Log。此外,他可以实现LogWarningLogError

另外,将来您可能希望添加 logLevel “Catastrophic”。在 C#8 之前,您无法在不破坏所有当前实现的情况下将方法 LogCatastrophic 添加到 ILogger。

【讨论】:

    【解决方案3】:

    另一个使界面独特的东西是covariance / contravariance

    说实话,我从来没有发现自己处于默认实现的情况。在界面中是解决方案。我对此有点怀疑。

    【讨论】:

      【解决方案4】:

      抽象类和新的默认接口方法都有其适当的用途。

      A.原因

      没有引入默认接口方法来替代抽象类。

      What's new in C# 8.0 状态:

      此语言功能使 API 作者能够在以后的版本中向接口添加方法,而不会破坏与该接口现有实现的源代码或二进制兼容性。现有实现继承默认实现。

      此功能还使 C# 能够与支持类似功能的面向 Android 或 Swift 的 API 互操作。默认接口方法还支持类似于“特征”语言功能的场景。

      B.功能差异

      抽象类和接口之间仍然存在显着差异(即使使用默认方法)。

      以下是接口仍然不能拥有/做的一些事情,而抽象类可以

      • 有一个构造函数,
      • 保持状态,
      • 从非抽象类继承,
      • 有私有方法。

      C.设计

      虽然默认接口方法使接口更加强大,但抽象/基类和接口仍然代表着根本不同的关系。

      (来自When should I choose inheritance over an interface when designing C# class libraries?

      • 继承描述的是一种关系。
      • 实现接口描述了一种可以做的关系。

      【讨论】:

      • 接口可以有私有方法,我们可以从该接口中其他公共成员的定义中调用它们。
      【解决方案5】:

      我想到的唯一主要区别是您仍然可以为接口永远不会拥有的抽象类重载默认构造函数。

      abstract class LivingEntity
      {
          public int Health
          {
              get;
              protected set;
          }
      
      
          protected LivingEntity(int health)
          {
              this.Health = health;
          }
      }
      
      class Person : LivingEntity
      {
          public Person() : base(100)
          { }
      }
      
      class Dog : LivingEntity
      {
          public Dog() : base(50)
          { }
      }
      

      【讨论】:

        【解决方案6】:

        两个主要区别:

        • 抽象类可以有状态,但接口不能。
        • 一个类型可以派生自一个抽象类,但可以实现多个接口。

        在默认修饰符方面还有一些其他较小的差异。

        【讨论】:

          猜你喜欢
          • 2018-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-03
          • 2012-03-18
          • 2010-12-27
          • 2016-11-24
          • 2012-07-19
          相关资源
          最近更新 更多