How to Resolve Error "CS0249: Do not override object.Finalize. Instead, provide a destructor." in C#
The Compiler Error CS0249 is a syntax restriction error. The message reads: "Do not override object.Finalize. Instead, provide a destructor."
In the .NET ecosystem, the System.Object class defines a method named Finalize() which is used by the Garbage Collector (GC) to clean up unmanaged resources before an object is destroyed. However, C# does not allow you to override this method directly using the override keyword. Instead, C# enforces the use of Destructor syntax (~ClassName), which the compiler automatically translates into a safe Finalize implementation.
This guide explains how to define finalization logic correctly in C#.
Understanding C# Destructors vs. Finalize
The reason C# forbids override void Finalize() is safety. When an object is finalized, it is critical that the base class's finalization logic also runs.
When you write a C# destructor:
~MyClass()
{
// Cleanup code
}
The compiler implicitly converts it into this structure during compilation (IL generation):
protected override void Finalize()
{
try
{
// Your Cleanup code
}
finally
{
base.Finalize(); // Guaranteed to execute
}
}
By preventing manual overrides, C# guarantees that base.Finalize() is always called inside a finally block, preventing resource leaks that could occur if a developer forgot to call the base method or if an exception occurred.
Scenario: Attempting Manual Override
This error occurs when a developer familiar with other .NET languages (or looking at the Object Browser) tries to override the method directly.
Example of error:
using System;
public class ResourceManager
{
// ⛔️ Error CS0249: Do not override object.Finalize. Instead, provide a destructor.
// C# forbids accessing this method directly.
protected override void Finalize()
{
Console.WriteLine("Cleaning up resources...");
// Even calling base.Finalize() here is not enough to satisfy the compiler.
base.Finalize();
}
}
Solution: Use Destructor Syntax (~)
To define finalization logic, use the tilde ~ followed by the class name. This is the C# syntax for a destructor.
Example of error:
using System;
public class ResourceManager
{
// ✅ Correct: Destructor syntax.
// The compiler will generate the 'override Finalize' logic for you.
~ResourceManager()
{
Console.WriteLine("Cleaning up resources...");
}
}
Destructors cannot have access modifiers (public, private), cannot take parameters, and cannot be called explicitly. They are called non-deterministically by the Garbage Collector.
Best Practices: Do You Even Need This?
It is very rare to need a destructor in modern C# applications.
- Managed Resources: Do NOT use a destructor to release managed objects (like Lists, or other Classes). The GC handles those automatically.
- Unmanaged Resources: If you handle raw Windows APIs, pointers, or file handles, you should implement the Dispose Pattern using
IDisposable.
The Recommended Pattern (IDisposable)
If you have a destructor, you should almost always have IDisposable as well to allow developers to clean up manually.
public class SafeResource : IDisposable
{
// 1. Implement Dispose for manual cleanup
public void Dispose()
{
ReleaseUnmanagedResources();
GC.SuppressFinalize(this); // Tell GC not to run the destructor
}
// 2. Use Destructor ONLY as a backup for unmanaged resources
~SafeResource()
{
ReleaseUnmanagedResources();
}
private void ReleaseUnmanagedResources()
{
// Free unmanaged memory/handles here
}
}
Conclusion
CS0249 enforces the safety mechanism of the .NET Garbage Collector.
- Never write:
override void Finalize(). - Write instead:
~ClassName(). - Even better: Implement
IDisposableand only use the destructor as a fallback if you are dealing with non-memory resources (like direct OS handles).