我真的不明白。
如果基类是抽象的,并且仅用于为程序集中定义的公共子类提供通用功能,为什么不将它声明为内部?
我不希望抽象类对程序集外的代码可见。我不希望外部代码知道它。
答案 0 :(得分:40)
更新:这个问题是the subject of my blog on November 13th of 2012。看看它有关这个问题的更多想法。谢谢你提出的好问题!
你是对的;它不一定是这样的。其他OO语言允许“私有继承”,因此D继承自B的事实只能通过能够看到B的代码来利用。
这是原始C#设计师的设计决定。不幸的是,我现在离开了我的办公桌 - 我需要休息几天才能度过这个漫长的周末 - 所以我没有1999年的语言设计笔记。如果我在回来的时候想到它,我会浏览它们,看看是否有理由做出这个决定。
我个人认为继承应该用来代表“是一种”关系;也就是说,继承应该表示用语言建模的域的语义。我尝试避免将继承用作代码共享机制的情况。正如其他人所提到的,如果您想要表示的是“此类与其他类共享实现机制”,那么最好选择组合继承。
答案 1 :(得分:37)
通过继承自类,您可以通过您的孩子公开基类的功能。
由于子类具有比其父级更高的可见性,因此您将暴露将受到保护的成员。
通过实施具有更高可见性的孩子,您不能违反父类的保护级别。
如果基类实际上是由公共子类使用,那么您也需要将父类公开。
另一种选择是让你的“父”保持内部,使其成为非抽象的,并使用它来组成你的子类,并使用一个接口来强制类来实现这些功能:
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(); }
}
答案 2 :(得分:14)
我认为你可以做的最接近的事情是通过使其构造函数内部来阻止其他程序集创建抽象类,引用MSDN:
内部构造函数阻止抽象类用作与抽象类不在同一程序集中的类型的基类。
然后你可以尝试在类中添加一个EditorBrowsableAttribute来尝试从Intellisense中隐藏它(尽管我说它实际上使用了混合结果)或者将基类放在嵌套的命名空间中,例如作为MyLibrary.Internals
将其与其他课程分开。
答案 3 :(得分:4)
我认为你们在这里混淆了一些问题,实际上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。
答案 4 :(得分:3)
我认为这会违反Liskov Substitution Principle。
在这种情况下,我使用了内部类并且更喜欢组合而不是继承。您的设计是否有任何禁止在内部类中包含所有此类功能的内容,然后让您的公共类包含此内部类的实例?