81

反对在接口上声明受保护的访问成员的论点是什么?例如,这是无效的:

public interface IOrange
{
    public OrangePeel Peel { get; }
    protected OrangePips Seeds { get; }
}

在这个例子中,接口IOrange将保证实现者至少OrangePips向他们的继承者提供一个实例。如果实施者愿意,他们可以将范围扩大到 full public

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    public OrangePips Seeds { get { return new OrangePips(6); } }
}

接口成员的目的protected是为继承者(子类)提供支持契约,例如:

public class SpecialNavelOrange : NavelOrange
{
    ...
    // Having a seed value is useful to me.
    OrangePips seeds = this.Seeds; 
    ...
}

(诚​​然,这对 s 不起作用struct

我在接口中看不到privateorinternal修饰符的太多情况,但同时支持publicandprotected修饰符似乎是完全合理的。


我将尝试通过将成员与s 完全分开来解释protected成员在s 上的效用:interfaceinterface

让我们想象一个新的 C# 关键字 ,support来强制继承合同,因此我们声明如下:

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

这将允许我们通过契约类为它们的继承者提供受保护的成员:

public class NavelOrange : IOrange, IOrangeSupport
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

这并不是特别有用,因为类已经通过protected首先提供成员来暗示这种契约。

但是我们也可以这样做:

public interface IOrange : IOrangeSupport
{
   ...
}

从而适用IOrangeSupport于所有实现IOrange并要求它们提供特定protected成员的类——这不是我们目前可以做的事情。

4

15 回答 15

63

我认为每个人都认为接口只有公共成员,没有实现细节。您正在寻找的是一个抽象类

public interface IOrange
{
    OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
    protected OrangeBase() {}
    protected abstract OrangePips Seeds { get; }
    public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

编辑:公平地说,如果我们有一个派生自类 Ornament 的 PlasticOrange,它只能实现 IOrange 而不能实现受 Seeds 保护的方法。没事儿。根据定义,接口是调用者和对象之间的契约,而不是类与其子类之间的契约。抽象类与我们接近这个概念一样接近。这很好。您实质上提出的是语言中的另一种构造,通过它我们可以将子类从一个基类切换到另一个基类,而不会破坏构建。对我来说,这没有意义。

如果要创建类的子类,则子类是基类的特化。它应该完全了解基类的任何受保护成员。但是,如果您突然想要切换基类,那么子类应该与任何其他 IOrange 一起使用是没有意义的。

我想你有一个公平的问题,但这似乎是一个极端的案例,老实说,我认为它没有任何好处。

于 2009-02-05T15:13:07.083 回答
54

不明白为什么要这个。如果您希望派生类提供特定方法的实现,请选择抽象基类。接口就是这样 - 接口。公共合同,没有别的。将接口视为规范,它描述了实现对外界的看法。两针插头的规范没有说明(至少我假设)它的内部结构应该是什么样的。它必须与插头插座接口兼容。 (来源:中国制造网插头

于 2009-02-05T14:43:16.597 回答
16

因为没有意义。接口是公开的合约。我是一个 IThing,因此如果被问到我会执行 IThing 方法。您不能要求 IThing 确认它执行它无法告诉您的方法。

于 2009-02-05T14:40:24.217 回答
10

存在接口以允许人们在不知道具体实现是什么的情况下访问您的类。它完全脱离了数据传递合约的实现。

因此,接口中的所有内容都必须是公开的。非公共成员仅在您有权访问实现时才有用,因此不会对接口定义做出有意义的贡献。

于 2009-02-05T14:40:20.737 回答
7

接口成员一个公共 API;诸如此类的东西protected是实现细节 - 接口没有任何实现。我怀疑您正在寻找的是显式接口实现:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}
于 2009-02-05T14:40:08.507 回答
5

从 C# 8.0(2019 年 9 月)开始,您可以在接口内使用访问修饰符

检查接口 c# 8.0 中的这些更改

在 C# 8.0 中使用默认接口方法更新接口

看到这些帖子

C# 8 接口:公共、私有和受保护的成员

深入了解 C# 8 接口

于 2021-04-11T14:27:26.153 回答
3

界面就像钥匙的形状

在此处输入图像描述

这不是关键。

这不是锁。

这只是纤细的接触点。

出于这个原因,接口的所有成员(定义密钥的形状)都必须是公共的。

对于打开锁的钥匙来说,重要的是它们都具有相同的形状。

通过公开形状(界面) ,您可以让其他人创建兼容的锁或兼容的钥匙。

否则,将其(接口)设置为内部您将不允许其他人创建兼容的锁或兼容的钥匙。

于 2017-11-01T16:25:00.530 回答
1

接口是向客户端承诺某些功能的合约。换句话说,接口的目的是能够将类型转换为它,并像这样将其传递给需要该接口保证的功能的代码。由于某种类型的客户端代码无法访问该类型的受保护成员,因此在接口中声明受保护项是没有意义的。

于 2009-02-05T14:48:34.713 回答
1

与抽象基类相比,受保护的接口将允许(抽象类的)“多重继承”,我会发现它有用一两次......

于 2019-10-12T23:24:28.647 回答
1

仅作记录:从 C# 8.0 开始,接口现在可以包含

  • 受保护的成员
  • 私人会员
  • 执行

作为底线,它引入了一些以前仅在支持多重继承的语言中可用的功能,例如多个基本成员的共享实现。

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/default-interface-methods-versions https://jeremybytes.blogspot.com/2019/11/c-8-interfaces -public-private-and.html

于 2021-09-11T11:10:37.160 回答
0

接口是关于某个对象可以做什么的,所以当使用实现该接口的类时,开发人员会期望所有成员都被实现,因此受保护的访问修饰符对接口没有任何意义。

于 2009-02-05T14:39:52.890 回答
0

一个接口只包含公共成员。受保护意味着您声明的任何内容仅对类和派生类实例可用。

于 2009-02-05T14:40:16.367 回答
0

当前的接口设计有一个合理的判断,即它为实现者提供了更大的灵活性。请记住,接口通常是由框架程序员编写的,而实现者是不同的人。强制执行将是不必要的苛刻。

于 2009-02-05T14:45:49.587 回答
0

通过实现一个接口,该类型声明它支持一组特定的方法。如果这些方法中的任何一个不是公共的,则调用者将无法使用它,因此该类型将不支持所述接口。

于 2009-02-05T14:49:49.733 回答
0

任何实现 .net 接口的类都必须包含所有接口成员的实现。此外,任何类都可以向派生类公开它希望的任何成员。要求接口的实现必须包含一个只能从派生类中使用的成员将没有任何用处,除非(1)这样的成员对接口外部的东西可见,或者(2)接口实现可以使用他们自己没有定义的成员。如果允许接口包含嵌套类(可以访问接口的protected成员),那么protected接口成员是有意义的。实际上,如果嵌套在接口中的类可以为该接口定义扩展方法,它们可能非常有用。不幸的是,不存在这样的设施。

顺便说一句,即使不能在接口中嵌套类,将internal访问修饰符应用于接口成员仍然很有用,其效果是只有定义接口的程序集才能为其定义任何实现。

于 2012-06-12T19:03:38.157 回答