C# Sealed Class: Everything you need to know

A thumbnail showing C# sealed class code.

C#: Sealed Class

In C#, a sealed class is a class that cannot be inherited by other classes. Once a class is marked as sealed, it cannot be used as a base class for any other class. Any attempt to derive a new class from a sealed class will result in a compile-time error.

Sealing a class is a way of ensuring that the class cannot be modified in unintended ways by other developers. It also allows the developer to guarantee certain class-level invariants, such as immutability. Additionally, sealing a class can improve the performance of the application by reducing the overhead associated with virtual method calls.

In this article, we will explore the use of sealed classes and methods in C#, as well as the benefits and limitations of using this modifier.

We will also examine other types that are inherently sealed, such as structs, enums, and the built-in string class. Additionally, we will delve into virtual methods, which are the opposite of sealed methods, and discuss how they can be used to allow modifications through inheritance while ensuring consistency and maintainability of the codebase.

C#: Public vs Sealed vs Abstract Classes

Public, sealed, and abstract are access modifiers that achieve different things in C#:

  • Public classes are accessible from anywhere within the program and can be inherited by other classes.
  • Abstract" classes are intended to be used as a base class and cannot be instantiated. They are intended to be overridden by derived classes.
  • Sealed classes cannot be inherited and cannot have any derived class. This provides a stronger level of encapsulation and protection against unintended modifications. Additionally, sealed classes are more efficient in terms of performance as they don't have virtual method calls

The table gives you a clear understanding of the main differences between the 3 access modifiers:

Modifier Can Inherit Can Instantiate Can Override Performance
Public Yes Yes Yes Normal
Abstract Yes No Yes Normal
Sealed No Yes No Greater

How to use the `sealed` keyword?

To use the "sealed" keyword on a class, add the "sealed" modifier before the class definition. For example:

C#
sealed class SealedClass
{

}

When should I seal a class?

Use a sealed class when you want to prevent other developers from creating a derived class and modifying the behavior of the class in unintended ways.

As a general rule, I always mark classes as sealed unless I'm sure I'll be using inheritance. Of course, you can always go back and unseal classes if needed.

Here are some specific scenarios where sealed classes can be useful:

  • Guaranteeing class-level invariants: For example, if you have a class that represents an immutable object, such as a string, you can use the sealed keyword to prevent other developers from creating a derived class that can modify the object's state.
  • Improving performance: Sealed classes don't have virtual method calls, so they can be more efficient in terms of performance. If you have a class that will be instantiated frequently, and you don't expect any derived classes, you can use the sealed keyword to improve the performance of your application.
  • Designing a class for a specific use case: If you are designing a class for a specific use case and you don't expect it to be used as a base class for other classes, you can use the sealed keyword to prevent other developers from creating a derived class that could break the intended behavior of the class.
  • Controlling modification through inheritance: If you don't want other developers to be able to modify the behavior of your class through inheritance, you can use the sealed keyword to prevent any derived classes from being created.

Sealed Class Performance

The performance gain from using sealed classes is generally small and may not be noticeable in most cases, but it's something you should consider if you are developing high-performing systems.

Virtual Methods

When comparing the performance of sealed and non-sealed methods, the main difference is in the way the JIT (Just-In-Time compiler) compiles them. Non-sealed methods require the JIT to use a virtual method call to ensure that the correct method is called at runtime, which adds overhead to the performance of the application. On the other hand, sealed methods allow the JIT to use a direct method call which is faster since the JIT knows that the variable is of the defined type and it cannot be an instance from a derived type.

The table below shows that sealed methods have faster performance than non-sealed methods:

MethodMeanErrorStdDevMedian
NonSealed0.2091 ns0.0782 ns0.2245 ns0.1447 ns
Sealed0.1563 ns0.0729 ns0.2149 ns0.0289 ns

Benchmark code:

C#
using BenchmarkDotNet.Attributes;

public class Base
{
    public virtual void Call() { }
}
public class NonSealed : Base
{
    public override void Call() { }
}
public sealed class Sealed : Base
{
    public override void Call() { }
}

public class SealedVsNonSealed
{
    readonly Sealed sealedType = new();
    public void NonSealed()
    {
        NonSealed nonSealed = new();
        nonSealed.Call();
    }

    [Benchmark]
    public void Sealed()
    {
        Sealed seal = new();
        seal.Call();
    }
}

Virtual vs Sealed Methods

Virtual and sealed methods are two different ways to control the behavior of a class through inheritance in C#.

Virtual methods allow for flexibility in modifying the behavior of a class through inheritance, while sealed methods provide a stronger level of encapsulation and protection against unintended modifications. Virtual methods can be overridden by derived classes to provide a specialized implementation, while sealed methods cannot. In terms of performance, virtual method calls add overhead to the performance, as the runtime must determine the correct implementation of a method to call at runtime. On the other hand, sealed methods do not have virtual method calls, which results in a performance boost.

Inherently Sealed Types

In C#, most types are inherently sealed, meaning that they cannot be inherited or modified by other classes.

The main reason Microsoft decided to seal classes is to ensure that the code does exactly what it was designed to do, no more and no less. In the trade-off between flexibility and robustness, Microsof leaned towards robustness as it leads to the development of a well-designed, fully-featured, robust, secure, predictable, and testable framework.

Some examples include:

  • Value types, such as structs and enums, do not support inheritance by design. This means that you cannot create a derived class from a struct or enum. This makes them inherently sealed and provides a level of protection against unintended modifications.
  • Built-in classes, such as the string class is also inherently sealed. This means that you cannot create a derived class from the string class and you cannot modify the state of a string object.

C# Sealed Class Examples

Prevent inheritance

C#
sealed class MySealedClass
{
    // class members
}

class MySubClass : MySealedClass // Compiler error: cannot inherit from a sealed class
{
    // class members
}

The code above will give you a compiler error:

Compiler error: cannot inherit from a sealed class

Prevent method overriding

Use the sealed modifier to prevent method overriding:

C#
class MyBaseClass
{
    public virtual void MyMethod() {}
}

class MyDerivedClass : MyBaseClass
{
    public sealed override void MyMethod() { }
}

class MySubDerivedClass : MyDerivedClass
{
    public override void MyMethod() // Compiler error: cannot override a sealed method
    {
    }
}

The code above will give you a compiler error:

Compiler error: cannot override a sealed method
Published on:
Download Free Software Developer Career Guide

I've used these principles to increase my earnings by 63% in two years. So can you.

Dive into my 7 actionable steps to elevate your career.