All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.csharp.S3881.html Maven / Gradle / Ivy

There is a newer version: 10.2.0.105762
Show newest version

Why is this an issue?

The IDisposable interface is a mechanism to release unmanaged resources, if not implemented correctly this could result in resource leaks or more severe bugs.

This rule raises an issue when the recommended dispose pattern, as defined by Microsoft, is not adhered to. See the Compliant Solution section for examples.

Satisfying the rule’s conditions will enable potential derived classes to correctly dispose the members of your class:

  • sealed classes are not checked.
  • If a base class implements IDisposable your class should not have IDisposable in the list of its interfaces. In such cases it is recommended to override the base class’s protected virtual void Dispose(bool) method or its equivalent.
  • The class should not implement IDisposable explicitly, e.g. the Dispose() method should be public.
  • The class should contain protected virtual void Dispose(bool) method. This method allows the derived classes to correctly dispose the resources of this class.
  • The content of the Dispose() method should be invocation of Dispose(true) followed by GC.SuppressFinalize(this)
  • If the class has a finalizer, i.e. a destructor, the only code in its body should be a single invocation of Dispose(false).
  • If the class inherits from a class that implements IDisposable it must call the Dispose, or Dispose(bool) method of the base class from within its own implementation of Dispose or Dispose(bool), respectively. This ensures that all resources from the base class are properly released.

Noncompliant code example

public class Foo1 : IDisposable // Noncompliant - provide protected overridable implementation of Dispose(bool) on Foo or mark the type as sealed.
{
    public void Dispose() // Noncompliant - should contain only a call to Dispose(true) and then GC.SuppressFinalize(this)
    {
        // Cleanup
    }
}

public class Foo2 : IDisposable
{
    void IDisposable.Dispose() // Noncompliant - Dispose() should be public
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public virtual void Dispose() // Noncompliant - Dispose() should be sealed
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

public class Foo3 : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Cleanup
    }

    ~Foo3() // Noncompliant - Modify Foo.~Foo() so that it calls Dispose(false) and then returns.
    {
        // Cleanup
    }
}{code}

Compliant solution

// Sealed class
public sealed class Foo1 : IDisposable
{
    public void Dispose()
    {
        // Cleanup
    }
}

// Simple implementation
public class Foo2 : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    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);
    }
}

// Base disposable class
public class Foo4 : DisposableBase
{
    protected override void Dispose(bool disposing)
    {
        // Cleanup
        // Do not forget to call base
        base.Dispose(disposing);
    }
}

Resources

Refer to





© 2015 - 2024 Weber Informatics LLC | Privacy Policy