Is it a right expectation that if a C# class deals with unmanaged resources and implements IDisposable, then it also should implement some kind of finalizer logic?
We have a vendor-supplied utility class that uses some unmanaged resources. We don't have the source code, so don't know too much implementation details, apart from the fact that it implements IDisposable but does not have any finalizer or SafeHandle. So without calling Dispose, it leaks. Simplified sample code:
public class Utility : IDisposable
{
//This class has some unmanaged resources
...
//Utility function
public void DoSomething(...) { ... }
//IDisposable
public void Dispose() { ... }
protected virtual void Dispose(bool disposing) { ... }
}
In our code we created a facade around it to simplify the usage and also added a singleton as it is used at dozens of places in our complex legacy codebase. Example:
public class UtilityFacade : IDisposable
{
protected Utility utility = new Utility();
//Simplified utility function
public void DoSomethingGood() { utility.DoSomething(1,2,3); }
//IDisposable
protected bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
utility.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//Singleton
public static UtilityFacade Instance { get; } = new UtilityFacade();
}
So from our applications (web site, web service, console apps) it would be used like this:
UtilityFacade.Instance.DoSomethingGood();
The problem is that since the Instance is a static member, it will never be disposed via IDisposable, so the Utility class will not be disposed either, and since it doesn't implement any finalizer, it leaks unmanaged resources at the end of the application process.
Which is the right choice here:
- The vendor says we should call Utility.Dispose() when the application finishes. This would require extra coding for us, e.g. hooking up to Application_End for web apps, or adding try{}finally{...} blocks to console apps for deterministic cleanup, or adding a finalizer to the facade class (which would keep the code related to Utility at one place at least).
- We request the vendor to implement the finalizer. Since the Utility class is dealing directly with the unmanaged resources, they should add the finalizer logic. According to some articles on the net it is the best practice recommended by Microsoft.
Or any other recommendation?