Why aren't variables declared in “try” in scope in “catch” or “finally”?

后端 未结 28 2428
时光说笑
时光说笑 2020-11-28 03:44

In C# and in Java (and possibly other languages as well), variables declared in a \"try\" block are not in scope in the corresponding \"catch\" or \"finally\" blocks. For e

相关标签:
28条回答
  • 2020-11-28 04:01

    Two things:

    1. Generally, Java has just 2 levels of scope: global and function. But, try/catch is an exception (no pun intended). When an exception is thrown and the exception object gets a variable assigned to it, that object variable is only available within the "catch" section and is destroyed as soon as the catch completes.

    2. (and more importantly). You can't know where in the try block the exception was thrown. It may have been before your variable was declared. Therefore it is impossible to say what variables will be available for the catch/finally clause. Consider the following case, where scoping is as you suggested:

      
      try
      {
          throw new ArgumentException("some operation that throws an exception");
          string s = "blah";
      }
      catch (e as ArgumentException)
      {  
          Console.Out.WriteLine(s);
      }
      

    This clearly is a problem - when you reach the exception handler, s will not have been declared. Given that catches are meant to handle exceptional circumstances and finallys must execute, being safe and declaring this a problem at compile time is far better than at runtime.

    0 讨论(0)
  • 2020-11-28 04:02

    @burkhard has the question as to why answered properly, but as a note I wanted to add, while your recommended solution example is good 99.9999+% of time, it is not good practice, it is far safer to either check for null before using something instantiate within the try block, or initialize the variable to something instead of just declaring it before the try block. For example:

    string s = String.Empty;
    try
    {
        //do work
    }
    catch
    {
       //safely access s
       Console.WriteLine(s);
    }
    

    Or:

    string s;
    try
    {
        //do work
    }
    catch
    {
       if (!String.IsNullOrEmpty(s))
       {
           //safely access s
           Console.WriteLine(s);
       }
    }
    

    This should provide scalability in the workaround, so that even when what you're doing in the try block is more complex than assigning a string, you should be able to safely access the data from your catch block.

    0 讨论(0)
  • 2020-11-28 04:03

    When you declare a local variable it is placed on the stack (for some types the entire value of the object will be on the stack, for other types only a reference will be on the stack). When there is an exception inside a try block, the local variables within the block are freed, which means the stack is "unwound" back to the state it was at at the beginning of the try block. This is by design. It's how the try / catch is able to back out of all of the function calls within the block and puts your system back into a functional state. Without this mechanism you could never be sure of the state of anything when an exception occurs.

    Having your error handling code rely on externally declared variables which have their values changed inside the try block seems like bad design to me. What you are doing is essentially leaking resources intentionally in order to gain information (in this particular case it's not so bad because you are only leaking information, but imagine if it were some other resource? you're just making life harder on yourself in the future). I would suggest breaking up your try blocks into smaller chunks if you require more granularity in error handling.

    0 讨论(0)
  • 2020-11-28 04:04

    According to the section titled "How to Throw and Catch Exceptions" in Lesson 2 of MCTS Self-Paced Training Kit (Exam 70-536): Microsoft® .NET Framework 2.0—Application Development Foundation, the reason is that the exception may have occurred before variable declarations in the try block (as others have noted already).

    Quote from page 25:

    "Notice that the StreamReader declaration was moved outside the Try block in the preceding example. This is necessary because the Finally block cannot access variables that are declared within the Try block. This makes sense because depending on where an exception occurred, variable declarations within the Try block might not yet have been executed."

    0 讨论(0)
  • 2020-11-28 04:04

    The variables are block level and restricted to that Try or Catch block. Similar to defining a variable in an if statement. Think of this situation.

    try {    
        fileOpen("no real file Name");    
        String s = "GO TROJANS"; 
    } catch (Exception) {   
        print(s); 
    }
    

    The String would never be declared, so it can't be depended upon.

    0 讨论(0)
  • 2020-11-28 04:04

    What if the exception is thrown in some code which is above the declaration of the variable. Which means, the declaration itself was not happend in this case.

    try {
    
           //doSomeWork // Exception is thrown in this line. 
           String s;
           //doRestOfTheWork
    
    } catch (Exception) {
            //Use s;//Problem here
    } finally {
            //Use s;//Problem here
    }
    
    0 讨论(0)
提交回复
热议问题