【发布时间】:2010-09-02 12:15:37
【问题描述】:
我真的不明白。
如果基类是抽象的并且仅用于为程序集中定义的公共子类提供通用功能,为什么不应该将其声明为内部的?
我不希望抽象类对程序集外的代码可见。我不想让外部代码知道它。
【问题讨论】:
标签: c# inheritance internal
我真的不明白。
如果基类是抽象的并且仅用于为程序集中定义的公共子类提供通用功能,为什么不应该将其声明为内部的?
我不希望抽象类对程序集外的代码可见。我不想让外部代码知道它。
【问题讨论】:
标签: c# inheritance internal
更新:这个问题是the subject of my blog on November 13th of 2012。有关此问题的更多想法,请参见它。谢谢你的好问题!
你是对的;它不必是这样的。其他 OO 语言允许“私有继承”,即 D 从 B 继承的事实只能被能够看到 B 的代码利用。
这是最初 C# 设计师的设计决定。不幸的是,我现在不在办公桌前——我将在长周末休假几天——所以我面前没有 1999 年的语言设计笔记。如果我回来后想到它,我会浏览它们,看看是否有这个决定的理由。
我个人的看法是,应该用继承来表示“是一种”的关系;也就是说,继承应该表示用语言建模的域的语义。我尽量避免将继承用作代码共享机制的情况。正如其他人所提到的,如果您想要表示的是“这个类与其他类共享实现机制”,那么最好选择组合而不是继承。
【讨论】:
通过从一个类继承,您可以通过您的子类公开基类的功能。
由于子类比其父类具有更高的可见性,因此您将暴露本应受到保护的成员。
您不能通过实现具有更高可见性的子类来违反父类的保护级别。
如果基类确实要供公共子类使用,那么您也需要将父类设为公共。
另一种选择是将“父”保持在内部,使其非抽象,并使用它来组合您的子类,并使用接口强制类实现功能:
public interface ISomething
{
void HelloWorld();
}
internal class OldParent : ISomething
{
public void HelloWorld(){ Console.WriteLine("Hello World!"); }
}
public class OldChild : ISomething
{
OldParent _oldParent = new OldParent();
public void HelloWorld() { _oldParent.HelloWorld(); }
}
【讨论】:
我认为您可以做的最接近的事情是通过将其构造函数设为内部来防止其他程序集创建抽象类,引用MSDN:
内部构造函数防止抽象类被用作与抽象类不在同一程序集中的类型的基类。
然后您可以尝试将EditorBrowsableAttribute 添加到类中以尝试将其隐藏在 IntelliSense 中(不过,老实说,我使用它的结果好坏参半)或将基类放在嵌套命名空间中,例如 @ 987654323@ 将其与您的其他课程分开。
【讨论】:
我认为您在这里混淆了关注点,实际上应该归咎于 C#(以及之前的 Java)。
继承应该作为一种分类机制,而它通常用于代码重用。
对于代码重用,大家都知道组合优于继承。 C# 的问题在于它为我们提供了一种简单的继承方式:
class MyClass : MyReusedClass { }
但是为了作曲,我们需要自己来做:
class MyClass {
MyReusedClass _reused;
// need to expose all the methods from MyReusedClass and delegate to _reused
}
缺少的是像trait (pdf) 这样的构造,它将使组合达到与继承相同的可用性级别。
有关于traits in C# (pdf) 的研究,它看起来像这样:
class MyClass {
uses { MyTrait; }
}
虽然我希望看到another model(Perl 6 角色的那个)。
更新:
作为旁注,Oxygene 语言有a feature,它允许您将接口的所有成员委托给实现该接口的成员属性:
type
MyClass = class(IReusable)
private
property Reused : IReusable := new MyReusedClass(); readonly;
implements public IReusable;
end;
在这里,IReusable 的所有接口成员都将通过MyClass 公开,并且它们都将委托给Reused 属性。不过,有一些 problems 采用这种方法。
另一个更新:
我已经开始在 C# 中实现这个自动组合概念:看看NRoles。
【讨论】:
我认为这违反了Liskov Substitution Principle。
在这种情况下,我使用了内部类并且更喜欢组合而不是继承。您的设计是否有任何内容禁止在内部类中包含所有此类功能,然后让您的公共类包含此内部类的实例?
【讨论】: