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

后端 未结 28 2558
时光说笑
时光说笑 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:12

    If we ignore the scoping-block issue for a moment, the complier would have to work a lot harder in a situation that's not well defined. While this is not impossible, the scoping error also forces you, the author of the code, to realise the implication of the code you write (that the string s may be null in the catch block). If your code was legal, in the case of an OutOfMemory exception, s isn't even guaranteed to be allocated a memory slot:

    // won't compile!
    try
    {
        VeryLargeArray v = new VeryLargeArray(TOO_BIG_CONSTANT); // throws OutOfMemoryException
        string s = "Help";
    }
    catch
    {
        Console.WriteLine(s); // whoops!
    }
    

    The CLR (and therefore compiler) also force you to initialize variables before they are used. In the catch block presented it can't guarantee this.

    So we end up with the compiler having to do a lot of work, which in practice doesn't provide much benefit and would probably confuse people and lead them to ask why try/catch works differently.

    In addition to consistency, by not allowing anything fancy and adhering to the already established scoping semantics used throughout the language, the compiler and CLR are able to provide a greater guarantee of the state of a variable inside a catch block. That it exists and has been initialized.

    Note that the language designers have done a good job with other constructs like using and lock where the problem and scope is well defined, which allows you to write clearer code.

    e.g. the using keyword with IDisposable objects in:

    using(Writer writer = new Writer())
    {
        writer.Write("Hello");
    }
    

    is equivalent to:

    Writer writer = new Writer();
    try
    {        
        writer.Write("Hello");
    }
    finally
    {
        if( writer != null)
        {
            ((IDisposable)writer).Dispose();
        }
    }
    

    If your try/catch/finally is hard to understand, try refactoring or introducing another layer of indirection with an intermediate class that encapsulates the semantics of what you are trying to accomplish. Without seeing real code, it's hard to be more specific.

提交回复
热议问题