为什么我不能拥有受保护的接口成员?

时间:2009-02-05 14:36:58

标签: c# interface protected access-modifiers

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

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

在此示例中,接口IOrange将保证实现者至少向其继承者提供OrangePips实例。如果实现者想要,他们可以将范围扩展为完整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成员对接口的意图是为 inheritors (子类)提供支持合同,例如:

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

(不可否认,这不适用于struct s)

我在界面中看不到privateinternal修饰符的大部分情况,但支持publicprotected修饰符似乎完全合理。


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

让我们设想一个新的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成员的所有类 - 这不是我们目前可以做的事情。

14 个答案:

答案 0 :(得分:55)

我认为每个人都强调了只有公共成员的接口,没有实现细节。您要找的是abstract class

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); } }
}

编辑:公平地说,如果我们有一个源自类装饰的PlasticOrange,它只能实现IO范围而不是Seeds保护方法。那样就好。根据定义,接口是调用者和对象之间的契约,而不是类及其子类之间的契约。抽象类和我们这个概念一样接近。这没关系。你基本上提出的是语言中的另一个构造,通过它我们可以在不破坏构建的情况下将子类从一个基类切换到另一个基类。对我来说,这没有意义。

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

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

答案 1 :(得分:48)

看不出为什么会想要这个。如果希望派生类提供特定方法的实现,请转到抽象基类。接口就是 - 接口。公共合同,没有别的。将接口视为规范,描述了实现应如何看待外部世界。两针插头的规格没有说明(至少我认为)它的内部结构应该是什么样的。它必须与插头插座兼容。 Plug
(来源:made-in-china.com

答案 2 :(得分:15)

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

答案 3 :(得分:9)

存在允许人们在不知道具体实现是什么的情况下访问您的类的接口。它完全将实现与数据传递合同分开。

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

答案 4 :(得分:7)

接口成员公共API;诸如protected之类的东西是实现细节 - 接口不具有任何实现。我怀疑你要找的是显式接口实现:

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

答案 5 :(得分:2)

自 C# 8.0(2019 年 9 月)起,您可以在界面内设置访问修饰符

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

Update interfaces with default interface methods in C# 8.0

查看这些帖子

C# 8 Interfaces: Public, Private, and Protected Members

A Closer Look at C# 8 Interfaces

答案 6 :(得分:1)

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

答案 7 :(得分:1)

界面就像键的形状一样。

enter image description here

这不是关键。

不是锁。

这只是一个苗条的接触点。

因此,界面的所有成员(定义键的形状)必须是公共的。

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

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

否则,使其(界面)内部,您将不允许其他人创建兼容锁或兼容密钥。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

界面仅包含公共成员。受保护意味着您声明的任何内容仅适用于类和派生类实例。

答案 10 :(得分:0)

当前的界面设计有合理的判断力,它为实施者提供了更大的灵活性。请记住,接口通常由框架程序员编写,而实现者则是不同的人。执行实施将是不必要的严厉。

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

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