My class implements IDisposable
and follows the pattern where
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
But Sonar is still telling me I need to implement the dispose pattern...
Sonar Rule 3881 (IDisposable should be implemented correctly)
Is this a defect with sonar or have I missed something?
I saw that you already fixed the issue, but in case someone else has the same problem, I will elaborate on the rule requirements.
The idea of this rule is to allow potential derived classes to correctly dispose the members of your class. Hence if your class is sealed, the rule assumes your class correctly disposes itself and does nothing (there is another rule, S2931 which checks if your class contains IDisposable
fields that need to be disposed).
If the class is not sealed, the rule checks if it has a base class that implements IDisposable
. If it has and your class also implements IDisposable
, the rule will recommend to remove your implementation (e.g. remove the IDisposable
interface from your class) and override the base class's protected Dispose(bool)
method.
If the base class does not implement IDisposable
, the rule requires a protected virtual Dispose(bool)
method (to allow the inheritors to correctly dispose your class).
If your class contains a finalizer, i.e. destructor, the rule checks if its content is a single invocation of Dispose(false)
.
The rule checks if the content of the Dispose()
method (the one from the interface) contains a single invocation of Dispose(true)
. If your class has a finalizer, the rule requires an additional call to GC.SuppressFinalize(this)
.
Basically these are the correct implementations of IDisposable
according to the rule:
Sealed class
public sealed class Foo1 : IDisposable
{
public void Dispose()
{
// Cleanup
}
}
Simple implementation
public class Foo2 : IDisposable
{
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
// Cleanup
}
}
Implementation with a finalizer
public class Foo3 : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Cleanup
}
~Foo3()
{
Dispose(false);
}
}