dotnet/runtime

Analyzer for cases when the `Dispose()` pattern is introduced after the fact

Open

#70,188 opened on Jun 3, 2022

View on GitHub
 (3 comments) (1 reaction) (0 assignees)C# (5,445 forks)batch import
api-approvedarea-System.Runtimecode-analyzercode-fixerhelp wanted

Repository metrics

Stars
 (17,886 stars)
PR merge metrics
 (Avg merge 12d 11h) (661 merged PRs in 30d)

Description

Imagine we shipped a V1 like this:

// V1
public class Foo : IDisposable
{
    public virtual void Dispose();
}

The class isn't sealed so the class was supposed to have implemented the Dispose()-pattern but didn't due to oversight. We can't "unvirtualize" Dispose() in V2, but we can add the Dispose(bool disposing):

// V2
public class Foo : IDisposable
{
    public virtual void Dispose()
    {
       Dispose(true);
    }

    public virtual void Dispose(bool disposing)
    {
       if (disposing)
       {
          // Implementation from Dispose() in V1
       }
    }
}

Now imagine some code that was built against V1 looks as follows:

public class Bar : Foo
{
    public override void Dispose()
    {
        // Some code
    }
}

We'd like this code to raise a diagnostic:

'Bar' should override 'Dispose(bool)', not 'Dispose()'.

A code fixer should also be made available that changes Bar as follows:

public class Bar : Foo
{
    public override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Some code
        }
    }
}

Similarly, we should have a diagnostic that flags calls from the finalizer to Dispose() or Dispose(true) and replace it to Dispose(false):

public class SomeClass
{
    ~SomeClass()
    {
       Dispose();     // Warning
       Dispose(true); // Also warning
    }
}

A code fixer offer to change the call site to Dispose(false).

Contributor guide