It seems that the official Microsoft guidelines on sealing have evolved since this question was asked ~9 years ago, and they moved from an opt-in philosophy (seal by default) to opt-out (don't seal by default):
X DO NOT seal classes without having a good reason to do so.
Sealing a class because you cannot think of an extensibility scenario
is not a good reason. Framework users like to inherit from classes for
various nonobvious reasons, like adding convenience members. See
Unsealed Classes for examples of nonobvious reasons users want to
inherit from a type.
Good reasons for sealing a class include the following:
- The class is a static class. See Static Class Design.
- The class stores security-sensitive secrets in inherited protected members.
- The class inherits many virtual members and the cost of sealing them
individually would outweigh the benefits of leaving the class
unsealed.
- The class is an attribute that requires very fast runtime
look-up. Sealed attributes have slightly higher performance levels
than unsealed ones. See Attributes.
X DO NOT declare protected or virtual members on sealed types.
By definition, sealed types cannot be inherited from. This means that
protected members on sealed types cannot be called, and virtual
methods on sealed types cannot be overridden.
✓ CONSIDER sealing members that you override. Problems that can result from introducing virtual members (discussed in Virtual Members)
apply to overrides as well, although to a slightly lesser degree.
Sealing an override shields you from these problems starting from that
point in the inheritance hierarchy.
Indeed, if you search the ASP.Net Core codebase, you will only find about 30 occurences of sealed class
, most of which are attributes and test classes.
I do think that immutability conservation is a good argument in favor of sealing.