C#是否具有私有继承和受保护继承的概念?

C#是否具有私有继承和受保护继承的概念?

Does C# have the notion of private and protected inheritance?

C#是否具有私有/受保护的继承的概念,如果没有,为什么?

C ++

1
2
3
4
5
6
<wyn>
class Foo : private Bar {
 public:
   ...
 };
</wyn>

C#

1
2
3
4
5
6
<wyn>
public abstract NServlet class : private System.Web.UI.Page
{
    // error"type expected"
}
</wyn>

我正在.aspx页中实现"类似于servlet"的概念,但我不希望具体的类具有查看System.Web.UI.Page基础内部的能力。


C#仅允许公共继承。 C ++允许所有这三种。公共继承暗含" IS-A"类型的关系,而私人继承暗含" Is-Implemented-Terms-Of"类型的关系。由于分层(或组合)以一种可能更简单的方式完成了此任务,因此私有继承仅在受保护成员绝对需要或虚拟函数需要它时才使用-根据Effective C ++项目42中的Scott Meyers。

我的猜测是C#的作者认为没有必要使用这种额外的方法来实现一个类的另一类。


No it doesn't. What would the benefit be of allowing this type of restriction?

私有继承和受保护继承对于封装(信息隐藏)很有用。 C ++支持受保护的*继承,尽管Java不支持。这是我的项目中的一个有用示例。

在第3方框架中有一个基类**。它具有数十种设置以及用于操作它们的属性和方法。当分配了各个设置时,基类不会做很多检查,但是如果遇到不可接受的组合,它将在以后生成异常。

我正在使用分配这些设置的方法(例如,从文件中分配精心制作的设置)来创建子类。最好拒绝代码的其余部分(在我的孩子类之外)操纵单个设置并将其弄乱的功能。

就是说,我认为在C ++(再次支持私有继承和受保护继承)中,可以将子类强制转换为父类,并可以访问父级的公共成员。 (另请参见Chris Karcher的文章)尽管如此,受保护的继承仍可以改善信息隐藏。如果需要将类B1的成员真正隐藏在其他类C1和C2中,则可以通过在C1和C2内创建类B1的受保护变量来进行安排。 B1的受保护实例将对C1和C2的孩子可用。当然,这种方法本身不会在C1和C2之间提供多态性。但是可以通过从公共接口I1继承C1和C2来添加多态(如果需要)。

***为简便起见,将使用"受保护"而不是"私有和受保护"。

**就我而言,是National Instruments Measurement Studio。

  • 缺口


通过将类中的相同成员声明为private并使用new关键字,可以隐藏继承的API,使其不被公共看到。请参阅从MSDN隐藏继承。


@bdukes:
请记住,您并没有真正隐藏成员。例如。:

1
2
3
4
5
6
7
8
9
10
11
class Base
{
   public void F() {}
}
class Derived : Base
{
   new private void F() {}
}

Base o = new Derived();
o.F();  // works

但这实现了与C ++中私有继承相同的功能,这是发问者想要的。


如果您希望NServlet类对Page一无所知,则应考虑使用Adapter模式。编写一个页面,该页面将托管NServlet类的实例。然后,根据您的确切工作,您可以编写各种只了解基类NServlet的类,而不必使用asp.net页面成员来污染您的API。


第一个解决方案:

受保护的内部行为在同一程序集中公开,在其他程序集上受到保护。

您将需要更改不通过继承公开的类的每个成员的访问修饰符。

尽管此解决方案要求并强制将要继承的类供另一个程序集使用,但它有一点限制。因此,在不知情的父级中选择仅由继承使用还是不由继承使用...通常,子级对架构更了解...

这不是一个完美的解决方案,但是它可能是添加接口以隐藏方法的更好的选择,并且仍然可以通过子类来隐藏使用父方法的可能性,因为您可能不容易强制使用该接口。

问题:

protected和private访问修饰符不能用于实现接口的方法。这意味着受保护的内部解决方案不能用于接口实现的方法。这是一个很大的限制。

最终解决方案:

我退回到接口解决方案来隐藏方法。

它的问题是能够强制使用该接口,以便要隐藏的成员总是被隐藏,然后肯定避免了错误。

要仅使用接口,只需使构造函数受保护并添加一个静态构造方法即可(我将其命名为New)。实际上,此静态New方法是一种工厂函数,它返回接口。因此,其余代码仅需使用接口!


我知道这是一个老问题,但是在编写C#时我已经遇到过几次了,我想知道...为什么不仅仅使用接口?

当您创建第三方框架类的子类时,还应使其实现公共接口。然后定义该接口,使其仅包含您希望客户端访问的方法。然后,当客户端请求该类的实例时,请为他们提供该接口的实例。

这似乎是C#接受的处理这类事情的方法。

我第一次这样做是在我意识到C#标准库没有字典的只读变体时。我想提供对字典的访问权限,但不想让客户能够更改字典中的项目。因此,我定义了一个" DictionaryEx 类:Dictionary ,IReadOnlyDictionary ,其中V:IV",其中K是键类型,V是实数值类型,IV是V类型的接口,可防止更改。 DictionaryEx的实现非常简单。唯一困难的部分是创建ReadOnlyEnumerator类,但是即使花费了很长时间。

我看到的这种方法的唯一缺点是,如果客户端尝试将您的公共接口动态转换为相关的子类。要阻止这种情况,请将您的班级设置为内部。如果您的客户将您的公共接口转换为原始基类,那么我认为对于他们来说,他们将自己的生命掌握在自己手中是很清楚的。 :-)


您可能想要一个与NServlet实现挂钩的ServletContainer类。在我的书中,不允许私有/受保护的继承并没有什么大不了的,并且可以使语言不致混淆-与LINQ等类似。我们已经有足够的东西要记住。


不,仅公共继承。


不,不是。允许这种限制有什么好处?


推荐阅读