C# 8 Using Declaration Scope Confusion

坚强是说给别人听的谎言 提交于 2020-04-13 06:36:47

问题


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.


回答1:


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.




回答2:


I'd like to see the real function that's using this. The compiler won't change scope or sequence of allocations or disposals willy-nilly. If you have a method like:

void foo()
{
    using(var ms = new MemoryStream())
    {
        using(var ms2 = new MemoryStream())
        {
            /// do something
        }
    }
}

Then the Dispose() order doesn't matter, so it's safe for the compiler to arrange things however it sees fit. There may be other cases where the order is important, and the compiler should be smart enough to recognize that. I wouldn't file that under "coincidence" so much as "good AST analysis."




回答3:


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===



来源:https://stackoverflow.com/questions/59378228/c-sharp-8-using-declaration-scope-confusion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!