1

I am not seeing the code analysis rule csharp_prefer_simple_using_statement aka "Use simple 'using' statement (IDE0063)" produce output when expected. I added some dummy code to a method in my project, like so:

using (var file = Image.FromFile(userName))
{
    System.Diagnostics.Debug.Assert(file != null);
}

My .sln-style Solution in VS 2022 includes several .csproj-style Projects (i.e. the "old way"). I have a .editorconfig file in the same folder as my .sln, and a variety of other built-in .NET analyzers and Roslynator analyzers work fine.

In the .editorconfig I have csharp_prefer_simple_using_statement = true:warning, and I also added dotnet_diagnostic.IDE0063.severity = warning for good measure. I have double-checked that neither are duplicated elsewhere in the config, and there are no other .editorconfig files anywhere in the solution/project folders.

Even though I know it's supposed to be superseded by the .editorconfig file, I found the same setting in VS Options and enabled it there too:

VS Options

And I also opened the project file (C# 10 / .NET 6 latest, btw), and set <AnalysisLevel>latest-recommended</AnalysisLevel>.

I have cleaned the build, restarted VS, and rebuilt, and I still see nothing in the Output, Error List, or in the editor indicating that it suggests simplifying the using statement. Again, I have many other code analysis rules that product output both live in the editor and in the build output & errors list.

Where am I going wrong, please?

EDIT: @Guru Stron's question tickled my spidey sense, and I discovered that while the first method here does not produce IDE0063, the latter does. Why?

public Stream GenerateReport()
{
    using (var reportContext = new ReportRenderContext(this.ReportTemplate))
    {
        reportContext.Render();
    }

    return this.FileStream;
}

public static int GetAreaOfImage(string fileName)
{
    using (var image = Image.FromFile(fileName))
    {
        return image.Size.Width * image.Size.Height;
    }
}
pbristow
  • 1,997
  • 4
  • 26
  • 46
  • 1
    Is provided one a full code snippet? Can you please post full method code? – Guru Stron Jul 04 '22 at 07:49
  • @GuruStron edited OP to address your point. Do you know something about situations where IDE0063 doesn't kick out? – pbristow Jul 04 '22 at 08:19
  • Yes, my guess was that you had some statements after `using` so compiler would not trigger warning due to different scopes for disposable resource. – Guru Stron Jul 04 '22 at 08:44

1 Answers1

3

using declaration works based on scope, resource will be disposed at the end of the scope, so the next one:

public Stream GenerateReport()
{
    using (var reportContext = new ReportRenderContext(this.ReportTemplate))
    {
        reportContext.Render();
    }

    return this.FileStream;
}

Is not analogous to:

public Stream GenerateReport()
{
    using var reportContext = new ReportRenderContext(this.ReportTemplate);
    reportContext.Render();
    return this.FileStream;
}

The latter one is analogous to:

public Stream GenerateReport()
{
    using (var reportContext = new ReportRenderContext(this.ReportTemplate))
    {
        reportContext.Render();
        return this.FileStream;
    }
} 

Which can have difference in some cases, so due to this compiler will not produce the warning (compiler is very smart and very dumb at the same moment, it does not "really" know what this.FileStream does. For example it can access the same resource as ReportRenderContext (like some file in non-shareable fashion) and disposing after return this.FileStream will introduce runtime error. Or this.FileStream can be just a relatively long operation and one of the main purposes of Dispose is to free resources as soon as they are not needed. There is "reverse" example when the 2nd snippet can fix a "bug" - in async context).

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • I get the general theory but in practice I don't understand the difference. If the using declaration disposes at the end of the current scope, then it disposes after the return statement but before execution continues in the calling method, right? Isn't that identical to the 3rd code block in your answer? – pbristow Jul 04 '22 at 08:49
  • @pbarranis 2nd and 3rd are identical, as written in my answer (and you should get the warning in case of 3rd). But 1st one is not identical to 2nd and 3rd. – Guru Stron Jul 04 '22 at 09:07
  • @gurustrong I see it would dispose of the reportContext later; is that the only reason I'm not getting the IDE0063? Are there other differences between the two that I'm not understanding? – pbristow Jul 04 '22 at 09:10
  • 2
    @pbarranis Yes, cause compiler is very smart and very dumb at the same moment. It does not know what `this.FileStream` does. For example it can access the same resource as `ReportRenderContext` (for example some file in non-shareable fashion) and disposing after `return this.FileStream` will introduce runtime error. Or `this.FileStream` can be just a relatively long operation and the whole purpose of `Dispose` is to free resources as soon as they are not needed. There is "reverse" example when the 2nd snippet can fix a "bug" - [in async context](https://stackoverflow.com/a/19103343/2501279) – Guru Stron Jul 04 '22 at 09:17