Curious C# using statement expansion

笑着哭i 提交于 2019-12-23 06:47:13

问题


I've run ildasm to find that this:

    using(Simple simp = new Simple())
    {
        Console.WriteLine("here");
    }

generates IL code that is equivalent to this:

    Simple simp = new Simple();
    try
    {
        Console.WriteLine("here");
    }
    finally
    {
        if(simp != null)
        {
            simp.Dispose();
        }
    }

and the question is why the hell does it check null in the finally? The finally block will only be executed if the try block is executed, and the try block will only be executed if the Simple constructor succeeds (I.e. does not throw an exception), in which case simp will be non-null. (If there is some fear that some intervening steps might come between the Simple constructor and the beginning of the try block, then that would really be a problem because then an exception might be thrown that would prevent the finally block from executing at all.) So, why the hell?

Putting aside (please) the argument of whether the using statement is better than try-finally, I write my try-finally blocks as:

    Simple simp = new Simple();
    try
    {
        Console.WriteLine("here");
    }
    finally
    {
        simp.Dispose();
        simp = null;        // sanity-check in case I touch simp again
                            // because I don't rely on all classes
                            // necessarily throwing
                            // ObjectDisposedException
    }

回答1:


No, the finally block will ALWAYS be executed. You may not be getting the object from a new but from some other function that returns your object - and it might return NULL. using() is your friend!

dss539 was kind enough to suggest I include his note:

using(Simple simp = null) 

is yet another reason that the expansion must check for null first.




回答2:


using(Simple simp = null) is yet another reason that the expansion must check for null first.




回答3:


MSDN on the using statement.

What I think is strange is that it doesn't expand to:

Simple simp = new Simple();
Simple __compilergeneratedtmpname = simp;
try
{
    Console.WriteLine("here");
}
finally
{
    if(__compilergeneratedtmpname != null)
    {
        __compilergeneratedtmpname.Dispose();
    }
}



回答4:


It appears that your comment:

"If there is some fear that some intervening steps might come between the Simple constructor and the beginning of the try block, then that would really be a problem because then an exception might be thrown that would prevent the finally block from executing at all."

is possibly dead on. See:

Atomicity & Asynchronous Exception Failures

I also want to note the issue(s) with WCF and using:

Avoiding Problems with the Using Statement and WCF Service Proxies which references:

Avoiding Problems with the Using Statement



来源:https://stackoverflow.com/questions/946999/curious-c-sharp-using-statement-expansion

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