Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design advice - When to use "virtual" and "sealed" effectively [closed]

Tags:

c#

inheritance

Start with the Microsoft Design Guidelines for Developing Class Libraries, particularly the Extensibility section, where you'll find articles on virtual members and sealing.

Quoting, here:

  • Do not make members virtual unless you have a good reason to do so and you are aware of all the costs related to designing, testing, and maintaining virtual members.
  • Do prefer protected accessibility over public accessibility for virtual members. Public members should provide extensibility (if required) by calling into a protected virtual member.

  • Do not seal classes without having a good reason to do so.

  • Do not declare protected or virtual members on sealed types.
  • Consider sealing members that you override.

Read the full articles, though.


First off, I agree with the other answers which suggest aggressively sealing anything that was not designed specifically to be extended. I do not agree that you need a reason to seal something; rather, you need a reason to leave something unsealed.

Your question is very general, so here's a general answer: your library presumably is a collection of features which can be used as tools to solve user problems. Each feature in your library is presumably there because you did some research, discovered that there was a user problem that needed solving, and solved it for them.

Each of those features has a certain cost associated with it. Some of that cost is in the past -- the time you've spent designing, implementing, testing, debugging and shipping the code. Some of that cost is yet to come: maintainance, reading bug reports, and so on. There are also more subtle costs, like perhaps maintaining backwards compatibility with one of your existing features will raise the cost of implementing a new feature tomorrow.

Extensibility is a feature too. It is a feature where if you get it wrong, the costs are almost entirely in the future. Treat it like any other feature: figure out whether it is a feature that your users really need, and whether its benefits pay for its costs. If you cannot clearly evaluate the benefit or the cost of extensibility then its pretty risky to implement it carelessly.


In my opinion, you can't really foresee what your users will eventually use this for. As such, it's generally a good idea NOT to seal anything unless there is some internal behavior you don't want users mucking about with (ie. they need to know that this has to be set first before you do that, etc..)

As for virtual, you would tend to make anything virtual that the end user may want to override. Events have reduced the need for virtual functions a great deal, but there are still times when you would want to make them virtual. In general, you need to think about how any given member function might need customization by an end user.


There have been plenty of times I've said "Dammit! Why is this class sealed!?", but I've never said "gosh - I wish they'd sealed that class!"

There's a good chance that someday a better programmer than you will want to extend your class, and will know what they're doing. I think it's rare that there's a good reason to seal.


Declaring a method virtual implies a certain contract: Your class accepts that it can be overridden and anticipates on that.

There usually is a clear reason to make something virtual. When in doubt: don't.

And sealed is just the opposite, you can state you don't want it to be overridden anymore. A secondary reason could be performance here, but I wouldn't use that too fast.


Controversial opinion: C# classes should be sealed by default.

If the class wasn't designed to be inherited and you haven't thought through the potential pitfalls or documented how to correctly inherit, then your class quite possibly will fail in strange ways if people override methods. When you don't seal your class, you are telling clients of your class that it is OK to derive from it and you will have to support this "interface" of your class in future to avoid breaking clients that choose to inherit from your class. This puts restrictions on how you can modify your class in the future.

So seal classes by default unless you explicitly want to allow it. And if you do want to allow it, make sure you document which methods should be overriden by making the virtual, and what the overridden methods must do to ensure that the class keeps working (such as calling the base method).