Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么不';“中声明的t变量”;试一试;在“范围内”;捕获;或;最后一句话;?_C#_Java_Exception_Scope_Language Design - Fatal编程技术网

C# 为什么不';“中声明的t变量”;试一试;在“范围内”;捕获;或;最后一句话;?

C# 为什么不';“中声明的t变量”;试一试;在“范围内”;捕获;或;最后一句话;?,c#,java,exception,scope,language-design,C#,Java,Exception,Scope,Language Design,在C#和Java(可能还有其他语言)中,“try”块中声明的变量不在相应的“catch”或“finally”块的作用域中。例如,以下代码不编译: try { String s = "test"; // (more code...) } catch { Console.Out.WriteLine(s); //Java fans: think "System.out.println" here instead } 在这段代码中,catch块中对s的引用发生编译时错误,因为s仅在try

在C#和Java(可能还有其他语言)中,“try”块中声明的变量不在相应的“catch”或“finally”块的作用域中。例如,以下代码不编译:

try {
  String s = "test";
  // (more code...)
}
catch {
  Console.Out.WriteLine(s);  //Java fans: think "System.out.println" here instead
}
在这段代码中,catch块中对s的引用发生编译时错误,因为s仅在try块的作用域中。(在Java中,编译错误是“s无法解析”;在C#中,是“名称s”在当前上下文中不存在”。)

此问题的一般解决方案似乎是在try块之前声明变量,而不是在try块内声明变量:

String s;
try {
  s = "test";
  // (more code...)
}
catch {
  Console.Out.WriteLine(s);  //Java fans: think "System.out.println" here instead
}
然而,至少对我来说,(1)这感觉像是一个笨拙的解决方案,(2)它导致变量的作用域比程序员预期的要大(方法的整个剩余部分,而不仅仅是在try-catch-finally的上下文中)


我的问题是,这个语言设计决策背后的基本原理是什么(Java、C#和/或任何其他适用的语言)

您如何确定您已到达catch块中的声明部分?如果实例化引发异常怎么办?

我的想法是,因为try块中的某些内容触发了异常,所以它的命名空间内容不可信-即引用catch块中的字符串“s”可能导致引发另一个异常。

如果它没有引发编译错误,您可以为方法的其余部分声明它,那么就没有办法只在try范围内声明它。这迫使你明确变量应该存在的位置,而不是做出假设 >无论如何,自动变量的范围受到环绕它的花键的限制。为什么有人会在花括号外插入一个try关键字来期望这有所不同呢?

你的解决方案正是你应该做的。您无法确定您的声明是否在try块中到达,这将导致catch块中出现另一个异常

它必须作为单独的作用域工作

try
    dim i as integer = 10 / 0 ''// Throw an exception
    dim s as string = "hi"
catch (e)
    console.writeln(s) ''// Would throw another exception, if this was allowed to compile
end try

如果赋值操作失败,您的catch语句将返回到未赋值变量的空引用。

两件事:

  • 通常,Java只有两个级别的作用域:全局和函数。但是,try/catch是一个例外(没有双关语)。当抛出异常并且异常对象获得分配给它的变量时,该对象变量仅在“catch”部分中可用,并在catch完成后立即销毁

  • (更重要的是)。您无法知道在try块中引发异常的位置。可能是在声明变量之前。因此,不可能确定catch/finally子句将使用哪些变量。请考虑下面的情况,其中的范围是按照您的建议:

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

  • 这显然是一个问题-当您到达异常处理程序时,将不会声明。考虑到捕获意味着要处理异常情况,并且最终必须执行,因此安全性和在编译时声明这是一个问题要比在运行时好得多。

    变量是块级别的,并且仅限于Try或Catch块。类似于在if语句中定义变量。想想这种情况

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

    字符串永远不会被声明,因此不能依赖它

    在您给出的特定示例中,初始化s不能引发异常。所以你可能认为它的范围可以扩大

    但一般来说,初始化器表达式可以抛出异常。如果一个变量的初始化器抛出了一个异常(或者在发生异常的另一个变量之后声明了该异常),那么该变量在catch/finally的作用域中是没有意义的

    此外,代码可读性也会受到影响。C中的规则(以及遵循它的语言,包括C++、java和C语言)很简单:变量范围遵循块。
    如果您希望一个变量在try/catch/finally的作用域内,而不是在其他任何地方,那么请将整个变量包装在另一组大括号(一个裸块)中,并在尝试之前声明该变量。

    传统上,在C风格的语言中,大括号内发生的事情将保留在大括号内。我认为,对于大多数程序员来说,让变量的生命周期跨越这样的作用域是不直观的。通过将try/catch/finally块括在另一个级别的大括号中,可以实现所需的功能。e、 g

    ... code ...
    {
        string s = "test";
        try
        {
            // more code
        }
        catch(...)
        {
            Console.Out.WriteLine(s);
        }
    }
    
    编辑:我想每个规则都有例外。以下是有效的C++:

    int f() { return 0; }
    
    void main() 
    {
        int y = 0;
    
        if (int x = f())
        {
            cout << x;
        }
        else
        {
            cout << x;
        }
    }
    
    int f(){return 0;}
    void main()
    {
    int y=0;
    if(int x=f())
    {
    
    正如RavenPoint指出的那样,每个人都希望变量是它们所定义的块的局部变量。
    try
    引入块,
    catch
    也引入块

    如果希望变量同时位于
    try
    catch
    ,请尝试将这两个变量都包含在块中:

    // here is some code
    {
        string s;
        try
        {
    
            throw new Exception(":(")
        }
        catch (Exception e)
        {
            Debug.WriteLine(s);
        }
    }
    

    它们不在同一作用域中的部分原因是,在try块的任何一点上,您都可以抛出异常。如果它们在同一作用域中,这将是一场等待中的灾难,因为根据抛出异常的位置,异常可能更加模糊


    至少当它在try块之外声明时,您可以确定抛出异常时变量的最小值;try块之前的变量值。

    ,因为try块和catch块是两个不同的块

    在下面的代码中,您希望在块A中定义的s在块B中可见吗

    { // block A
      string s = "dude";
    }
    
    { // block B
      Console.Out.WriteLine(s); // or printf or whatever
    }
    

    简单的答案是C语言和大多数继承了它的语法的语言都是块作用域的,这意味着如果一个变量定义在一个块中,即{}内,那就是它的作用域

    顺便说一句,JavaScript是个例外,它的语法类似bu
        try
        {
             //Code 1
             String s = "1|2";
             //Code 2
        }
        catch
        {
             Console.WriteLine(s.Split('|')[1]);
        }
    
    {
         String s;
         try
         {
              s = "test";
              //More code
         }
         catch
         {
              Console.WriteLine(s);
         }
    }
    
    string s = String.Empty;
    try
    {
        //do work
    }
    catch
    {
       //safely access s
       Console.WriteLine(s);
    }
    
    string s;
    try
    {
        //do work
    }
    catch
    {
       if (!String.IsNullOrEmpty(s))
       {
           //safely access s
           Console.WriteLine(s);
       }
    }
    
     try (FileReader in = makeReader(), FileWriter out = makeWriter()) {
           // code using in and out
     } catch(IOException e) {
           // ...
     }
    
    with(FileReader in : makeReader()) with(FileWriter out : makeWriter()) {
        // code using in and out
    }
    
    static void TryCatchFinally()
    {
        StreamReader sr = null;
        try
        {
            sr = new StreamReader(path);
            Console.WriteLine(sr.ReadToEnd());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        finally
        {
            if (sr != null)
            {
                sr.Close();
            }
        }
    }
    
    .method private hidebysig static void  TryCatchFinallyDispose() cil managed
    {
      // Code size       53 (0x35)    
      .maxstack  2    
      .locals init ([0] class [mscorlib]System.IO.StreamReader sr,    
               [1] class [mscorlib]System.Exception ex)    
      IL_0000:  ldnull    
      IL_0001:  stloc.0    
      .try    
      {    
        .try    
        {    
          IL_0002:  ldsfld     string UsingTest.Class1::path    
          IL_0007:  newobj     instance void [mscorlib]System.IO.StreamReader::.ctor(string)    
          IL_000c:  stloc.0    
          IL_000d:  ldloc.0    
          IL_000e:  callvirt   instance string [mscorlib]System.IO.TextReader::ReadToEnd()
          IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)    
          IL_0018:  leave.s    IL_0028
        }  // end .try
        catch [mscorlib]System.Exception 
        {
          IL_001a:  stloc.1
          IL_001b:  ldloc.1    
          IL_001c:  callvirt   instance string [mscorlib]System.Exception::ToString()    
          IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)    
          IL_0026:  leave.s    IL_0028    
        }  // end handler    
        IL_0028:  leave.s    IL_0034    
      }  // end .try    
      finally    
      {    
        IL_002a:  ldloc.0    
        IL_002b:  brfalse.s  IL_0033    
        IL_002d:  ldloc.0    
        IL_002e:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()    
        IL_0033:  endfinally    
      }  // end handler    
      IL_0034:  ret    
    } // end of method Class1::TryCatchFinallyDispose
    
    // won't compile!
    try
    {
        VeryLargeArray v = new VeryLargeArray(TOO_BIG_CONSTANT); // throws OutOfMemoryException
        string s = "Help";
    }
    catch
    {
        Console.WriteLine(s); // whoops!
    }
    
    using(Writer writer = new Writer())
    {
        writer.Write("Hello");
    }
    
    Writer writer = new Writer();
    try
    {        
        writer.Write("Hello");
    }
    finally
    {
        if( writer != null)
        {
            ((IDisposable)writer).Dispose();
        }
    }
    
    string html = new Func<string>(() =>
    {
        string webpage;
    
        try
        {
            using(WebClient downloader = new WebClient())
            {
                webpage = downloader.DownloadString(url);
            }
        }
        catch(WebException)
        {
            Console.WriteLine("Download failed.");  
        }
    
        return webpage;
    })();
    
    try {
    
           //doSomeWork // Exception is thrown in this line. 
           String s;
           //doRestOfTheWork
    
    } catch (Exception) {
            //Use s;//Problem here
    } finally {
            //Use s;//Problem here
    }