Skip to content
Code quality Reviewed 2026-09-13

Destructor Throw

What does this mean ?

C# syntax such as ~Example() declares a finalizer. It is not a C++ destructor executed deterministically when a local variable leaves scope. The garbage collector controls finalization timing, and an unhandled finalizer exception can terminate the process.

What can happen ?

Cleanup can disrupt application availability or occur too late for resource needs. Finalizers must not depend on other managed objects being finalized in a particular order. This reliability concern requires context before assigning security impact.

Recommendation

Do not throw from a finalizer. Prefer SafeHandle for unmanaged handles and IDisposable/using for deterministic cleanup. Do not add an empty finalizer to a class that has no finalization requirement. Catching every exception without a cleanup design is not an adequate replacement.

Sample Code

// Incorrect: never run this example to test the process-termination behavior.
class BrokenFinalizer
{
    ~BrokenFinalizer() { throw new NotImplementedException(); }
}

A class owning no unmanaged resource needs no finalizer:

sealed class Label
{
    public string Text { get; }
    public Label(string text) { Text = text; }
}

For an owned disposable resource, follow the separate disposal pattern rather than copying this resource-free class.

Regression checks

Review whether a finalizer is needed at all. Test deterministic disposal through a fake owned resource, including repeated disposal. Do not rely on forcing garbage collection as the normal cleanup mechanism or throw from a production finalizer to test error handling.

References