C# quiz - try-finally

So what is the output for following program?

public class SimpleTest

{

      public static void Main(string[] args) {

            Console.WriteLine(GetString());

            Console.ReadLine();

      }

     

      private static string GetString() {

            string str = "original string";

            try {

                  return str;

            } finally {

                  str = "changed in finally";

            }

      }

}

It looks very simple, but most of my developer friends and I all had the wrong answer. In the college, we were all told that finally block is guaranteed to be executed before a method returns, right? So it should display “changed in finally”, shouldn’t it? Unfortunately, this is a wrong answer. The program will actually print “original string”!

So, why? The answer is pretty simple. Though “return str;” is just one statement in C#, it is made of a few IL instructions. So if we have a look the complied IL code, the program first loads the “original string” and stores it in location0, then in the try block, it loads the value from lcoation0 and then store it into location1. In the finally block, it loads string “changed in finally” and store it to location0. And at the end, it loads the value from location1 onto stack for return value and exits the method.

So we can simply put, the string “original string” is prepared for return before the finally block gets executed, that is why the “original string” was returned from the method.

.method private hidebysig static string  GetString() cil managed

{

  // Code size       24 (0x18)

  .maxstack  1

  .locals init (string V_0,

           string V_1)

  IL_0000:  nop

  IL_0001:  ldstr      "original string"

  IL_0006:  stloc.0

  .try

  {

    IL_0007:  nop

    IL_0008:  ldloc.0

    IL_0009:  stloc.1

    IL_000a:  leave.s    IL_0015

  }  // end .try

  finally

  {

    IL_000c:  nop

    IL_000d:  ldstr      "changed in finally"

    IL_0012:  stloc.0

    IL_0013:  nop

    IL_0014:  endfinally

  }  // end handler

  IL_0015:  nop

  IL_0016:  ldloc.1

  IL_0017:  ret

} // end of method SimpleTest::GetString

Print | posted on Thursday, November 27, 2008 9:01 PM

Feedback

# re: C# quiz - try-finally

Left by Tim Smith at 11/28/2008 2:14 AM
Gravatar This is why I have always felt that programmers need to learn more about how computers actually work. I wasn't fooled by this question because my first thought was "well, that depends on what they mean by return, language or IL/machine level".

Good post :)

# re: C# quiz - try-finally

Left by nightshade427 at 12/1/2008 8:56 AM
Gravatar Even without looking to the IL this makes complete sense since finally blocks are used for resource cleanup.

Lets say you were using a stream in the try block. You wouldn't want the finally block to clean up that stream before you return data from it or you will always get an exception. So it make sense that the try block prepares the return values before calling finally block.

# re: C# quiz - try-finally

Left by Roy Lawson at 12/1/2008 2:12 PM
Gravatar What the last guy said ;-) Resource cleanup ;-)

But, good post. That may be a gotcha for new developers.

# re: C# quiz - try-finally

Left by Changhong at 12/1/2008 6:40 PM
Gravatar nightshade427 & Roy - I don't think the behavior I discussed is directly useful for resource cleanup.

If you were thinking about something like this:
try {
return str;
} finally {
str = null;
}
This is not necessary and only add some noise into your code.

If you were thinking about something like this:
try {
return stream;
} finally {
stream.Dispose();
}
This is not going to work.

If you were thinking about something like this:
try {
return stream.Read();
} finally {
stream.Dispose();
}
Then it is not really relevant to my post.

However, it can be useful for cleanup resource in another language like javascript. See my post: http://geekswithblogs.net/FrostRed/archive/2008/11/29/127440.aspx

# re: C# quiz - try-finally

Left by Glenn at 12/17/2008 10:14 AM
Gravatar Another thing to point out is that this is the expected behavior of a stack frame and the fact that a string is a reference type and is immutable.

If you replaced the string with some other reference type and then mutate it's contents, I expect you will see the change. As the return would be the reference to the object, so any change to the object would be visible through that reference.

However, if you load it with a value type then you would get the same results.

In any event, Nightshade is correct, the functional intent of a finally block is to clean up or release any resources that are no longer needed, and shouldn't be left to wait for the GC.

# re: C# quiz - try-finally

Left by Dave at 12/28/2008 4:48 AM
Gravatar Heh... got it right. While it is true that the finally{} block will execute before the method ends, the finaly{} block will NOT execute before the try{}. Therefore, the string is set to "original string", it is returned, and then set to "changed in finally". Makes perfect sense.

And I completely agree with Tim (first post) on this count. I have had no formal training of any sort, and I think it gives me an advantage because I don't think in terms of how things are *supposed* to work... I know them for how they *do* work.

# re: C# quiz - try-finally

Left by Ben at 1/3/2009 7:30 AM
Gravatar That is why I always use one return statement and I place it at the end of the method. It avoids misinterpreting the result.


Good post though!

# re: C# quiz - try-finally

Left by shobhna at 3/16/2009 8:50 PM
Gravatar changed in finally

# re: C# quiz - try-finally

Left by Rob at 10/11/2010 10:52 AM
Gravatar I think it is still good to put your cleanup codes, like dispose(), in the finally block since it still gets executed before control gets transfered to the calling module.

# re: C# quiz - try-finally

Left by anand singh sengar at 4/18/2011 12:22 AM
Gravatar i think it was a simple code.
no one can do any mistake for answering this type of code..
thank you for suggesting me this type of puzzel

# re: C# quiz - try-finally

Left by girish at 6/8/2011 11:03 PM
Gravatar can fianlly block excuted without catch bloc?

# re: C# quiz - try-finally

Left by Rajni Jaltare at 11/9/2011 10:14 PM
Gravatar the output is finally block is wrong because finally block is used when the code gaurantee is excuted but this place finally block is used to term output

Your comment:





 

Copyright © Changhong Fu

Design by Bartosz Brzezinski

Design by Phil Haack Based On A Design By Bartosz Brzezinski