Is there ever a good case to use private or protected classes?
Is there ever a good case to use protected virtual/abstract members?
I think the answer is no, most of the time, to both questions.
I value unit testing, testability, composition over inheritance, and the single responsibility principle more than encapsulation.
If a set of members deserves to be its own class then it should be directly unit tested. Protected classes could be tested by unit tests that are in the same assembly as the test subject. I do not think this is a best practice: housing unit tests in the same assembly as the production code. What is driving the desire to hide the type with private or protected? The only answer I have ever heard was to prevent a developer using the type when they should not. This is a smell to me. It smells like the API design does not make clear to the consumer how to do what they want to do. If it was they would not be using classes that they should not be. If the class was in a namespace that a consumer had no reason to be using/importing they will be unlikely to use it. It could even be placed in an assembly that the consumer would have no reason to reference. Beyond that it could even be obfuscated after having been unit tested. Every one of these solutions simply increases the effort a consumer will have to go to to even know about the type yet alone utilize it. The best solution is make it easy for the consumer to know what to do.
Protected members only come into play when sub-classing a base class: inheritance (some people are more specific and call this implementation inheritance, not to be confused with interface inheritance). Excluding edge cases (like CollectionBase and DictionaryBase) the only reason I have seen presented for using inheritance is to implement the Template Method pattern (also know as the Hollywood pattern). I think a better solution to the problem that the Template Method pattern is trying to solve uses composition over inheritance. Use the refactoring Extract Class on all the methods that are protected virtual/abstract in the base class and Extract Interface on the extracted class.
This is a much easier solution to unit test. It is easier to unit test ControlFlow than TemplateBase. It is also much easier to unit test MySpecializer than MyTemplate. The situation gets more complicated if you introduce virtuals (virtual in C#, overrideable in VB.NET)not just pure virtuals (abstract in C#, mustoverride in VB.NET). A sub-class author can not know for certain if they should call on the base classes member they are overriding: base.DoIt(). Nor can they be sure when they should call it if they determine that they should call it (i.e. should it be called first, last, or somewhere in the middle). The sub-class author will have to read the source code of the base class to figure this out. This can cause maintenance issues for the base class author as well. The base class author needs to understand when each of the sub-classes is calling the base method from their override. If the base class author does not account for this bugs can easily be introduced. Composition over inheritance provides an easier solution to maintain than the Template Method pattern for both the base class and sub-class authors. The Template Method pattern smells to me of breaking the single responsibility principle. In my experience it may not start out that way but it usually ends up that way.16,839 Total Views