Abstract Class Design: Why not define public constructores?

纵然是瞬间 提交于 2019-12-04 10:05:33

Let's look at each of the cases.

Recommended:

  • protected - The most obvious case - all subclasses can call the constructor, irrespective of which assembly they reside in (as long as the the abstract base-class itself is visible to them).

  • internal - Useful when you want the abstract type to be publicly visible, but not publicly inheritable. In this case, you would want to make all of the non-private constructors internal. Only subclasses within the same assembly as the abstract base-class would be able to call the constructors - effectively, only they would be able to inherit. Another use-case would be if you wanted a 'special' constructor that should only be visible to same-assembly subclasses.

  • private - Used mainly for 'dirty-work' constructors that are targeted by other constructors of the abstract class when it uses constructor-chaining. The only other use, when all the constructors are private, is to only allow subclassing by nested classes, which do have access to private members of the containing-type.


Not recommended:

  • public - Not useful, behaves identically to protected. Only subclasses can call the constructor anyway, since the base-class is abstract.

  • protected internal - This too is no different from protected. The protected internal accessibility level means protected OR internal, not protected AND internal. However, the internal modifier here serves no purpose - it doesn't prevent subclasses residing outside the assembly from calling the constructor (assuming the abstract base-class is public) since they can rely on protected access, nor does it allow same-assembly types that are not subclasses from calling it (the type is abstract).

The key point here is that every non-private constructor in an abstract class is already at best protected. The vanilla internal-modifier strengthens restrictions on who can call the constructor. public and protected internal don't accomplish anything because they appear to weaken restrictions, but don't really succeed in doing so.

n C#, we are not able to instantiate an abstract class. So, does it still matter to define public constructors for abstract classes in C# ? Or not writing public constructors for abstract classes is because of the semantic meaning?

Exactly. You don't want the user to see an accessible constructor, but when they call it, they get a compile error.

Define internal constructors ?? In (1), it tells us that not defining internal protected constructors is because that "Constructors with public or protected internal visibility are for types that can be instantiated". Doesn't defining internal constructors for abstract classes break the rules in (1) ?

I believe rule 1 is about public and protected internal rule 2 is about protected and internal. So there's no intersection between the two.

Years passed. I think I have better understanding of this question now. So I would like to add some more input besides Ani's excellent answer.

In C#, we are not able to instantiate an abstract class. So, does it still matter to define public constructors for abstract classes in C# ?

It doesn't matter to the compiler, but it does matter to code readers. Public constructors in abstract types is misleading to code readers (they might think they can be instantiated).

Define internal constructors ?? In (1), it tells us that not defining internal protected constructors is because that "Constructors with public or protected internal visibility are for types that can be instantiated". Doesn't defining internal constructors for abstract classes break the rules in (1) ?

If we want the abstract class to be inheritable only by subclasses within the same assembly, obviously we cannot use protected (otherwise it can be inherited outside the assembly). Now we have some options to choose:

  • public - As mentioned above, public is misleading to code readers. Don't use it.

  • private - We want the abstract class to be inheritable by subclasses within the same assembly, not just by nested subclasses, so private won't work.

  • protected internal - We'll never need it because it's no different from protected.

  • internal - It is misleading to code readers, but we have no other choice. I would think it a trade-off.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!