Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# 8 Using Declaration Scope Confusion

With the new C# 8 Using Declaration Syntax, what is containing scope of a second consecutive using statement?

TL;DR

Previous to C# 8, having a consecutive using statement like:

using(var disposable = new MemoryStream())
{
    using(var secondDisposable = new StreamWriter(disposable))
    {}
}

would expand to something like the following (My Source):

MemoryStream disposable = new MemoryStream();
try {
    {
        StreamWriter secondDisposable = new StreamWriter(disposable);    
        try{
            {}
        }
        finally {
            if(secondDisposable != null) ((IDisposable)secondDisposable).Dispose();
        }
    }
}
finally {
    if(disposable != null) ((IDisposable)disposable).Dispose();
}

I know that there are two other possible expansions but they all are roughly like this

After upgrading to C# 8, Visual studio offered a Code Cleanup suggestion that I'm not certain I believe is an equivalent suggestion.

It converted the above consecutive using statement to:

using var disposable = new MemoryStream();
using var secondDisposable = new StreamWriter(disposable);

To me this changes the second's scope to the same scope as the first. In this case, It would probably coincidentally dispose of the streams in the correct order, but I'm not certain I like to rely on that happy coincidence.

To be clear on what VS asked me to do: I first converted the inner (which made sense because the inner was still contained in the outer's scope). Then I converted the outer (which locally made sense because it was still contained in the method's scope). The combination of these two clean ups is what I'm curious about.

I also recognize that my thinking on this could be slightly (or even dramatically) off, but as I understand it today, this doesn't seem correct. What is missing in my assessment? Am I off base?

The only thing I can think of is that there is some sort of an implicit scope inserted in the expansion for everything following a declaration statement.

like image 926
Justin Blakley Avatar asked Dec 17 '19 16:12

Justin Blakley


2 Answers

In this case, It would probably coincidentally dispose of the streams in the correct order, but I'm not certain I like to rely on that happy coincidence.

From the spec proposal:

The using locals will then be disposed in the reverse order in which they are declared.

So, yes, they already thought about it and do the disposal in the expected order, just as chained using statements would before it.

like image 96
Damien_The_Unbeliever Avatar answered Nov 11 '22 03:11

Damien_The_Unbeliever


To Illustrate the Daminen's answer; When you have a method something like;

public void M() 
{
    using var f1 = new System.IO.MemoryStream(null,true);    
    using var f2 = new System.IO.MemoryStream(null,true);
    using var f3 = new System.IO.MemoryStream(null,true);
}

IL converts it into;

public void M()
{
    MemoryStream memoryStream = new MemoryStream(null, true);
    try
    {
        MemoryStream memoryStream2 = new MemoryStream(null, true);
        try
        {
            MemoryStream memoryStream3 = new MemoryStream(null, true);
            try
            {
            }
            finally
            {
                if (memoryStream3 != null)
                {
                    ((IDisposable)memoryStream3).Dispose();
                }
            }
        }
        finally
        {
            if (memoryStream2 != null)
            {
                ((IDisposable)memoryStream2).Dispose();
            }
        }
    }
    finally
    {
        if (memoryStream != null)
        {
            ((IDisposable)memoryStream).Dispose();
        }
    }
}

Which is same as nested using statements you can check from here: https://sharplab.io/#v2:CYLg1APgAgTAjAWAFBQMwAJboMLoN7LpGYZQAs6AsgBQCU+hxTUADOgG4CGATugGZx0AXnQA7AKYB3THAB0ASQDysyuIC2Ae24BPAMoAXbuM5rqogK4AbSwBpD58bQDcTRkyKsOPfjGFipMgrKqpo6BkYmZla29o5Obu6eXLx8GCIS0lBySirqWnqGxqYW1nbcDs4JAL7IVUA===

like image 1
ilkerkaran Avatar answered Nov 11 '22 03:11

ilkerkaran