zoukankan      html  css  js  c++  java
  • C#中关于变量的作用域不易理解的特例

    变量的作用域的基本规则是很简单容易理解的,但有几个特例实在是很费解。

    第一个,使用循环时:

     1         static void Main(string[] args)
     2         {
     3             string str1 = "Hello1";     // 声明并初始化的话单步执行的时候正常执行
     4             Console.WriteLine("{0}", str1);    // 正常访问
     5 
     6             string str2;                // 只是声明的话单步执行的时候会跳过该行
     7             str2 = "Hello2";            // 先声明再初始化
     8             Console.WriteLine("{0}", str2);    // 正常访问
     9 
    10             Test1();
    11             Test2();
    12             Test3();
    13         }
    14 
    15         static void Test1()    // 在单独的块中初始化
    16         {
    17             string str3;
    18             {
    19                 str3 = "Hello3";      // 先声明再在单独的块中初始化
    20             }
    21             Console.WriteLine("{0}", str3);    // 出了块仍可以正常访问
    22 
    23             string str4;
    24             {
    25                 //string str5;     // 此处声明的变量出了块无法访问
    26                 {
    27                     str4 = "Hello4";     // 先声明再在嵌套的块中初始化
    28                 }
    29             }
    30             Console.WriteLine("{0}", str4);    // 出了块仍可以正常访问
    31             //Console.WriteLine("{0}", str5);    // error CS0103: 当前上下文中不存在名称“str5”
    32         }
    33 
    34         static void Test2()    // 初始化text
    35         {
    36             string text = null;     // 声明并初始化
    37             for (int i = 0; i < 10; i++)
    38             {
    39                 text = "Line " + Convert.ToString(i);
    40                 Console.WriteLine("{0}", text);
    41             }
    42             Console.WriteLine("Last text output in loop: {0}", text);
    43         }
    44 
    45         static void Test3()    // 未初始化text,虽在循环中赋值,但出了循环不能访问,编译错误
    46         {
    47             string text;          // 仅声明而不初始化
    48             for (int i = 0; i < 10; i++)    // 如为在for括号内初始化的变量,出了循环仍能使用
    49             {
    50                 text = "Line " + Convert.ToString(i);    // 循环内初始化
    51                 Console.WriteLine("{0}", text);
    52             }
    53             //Console.WriteLine("Last text output in loop: {0}", text);
    54             // error CS0165: 使用了未赋值的局部变量“text”(推测:循环块和普通块可能不完全一样)
    55         }

    Test3()中,仅声明而不初始化text变量,虽在循环中赋值,但出了循环不能访问,编译错误。如果使用C语言,这种方式实测是完全没问题的,但C#不知为什么不行,为什么这么设计。

    在C#高级编程(忘了第几版了),是这么说的:

    * 循环之前赋给text空字符串(或null),而在循环之后的代码中,该text就不会是空字符串了,其原因并不明显。
    * 这种情况的解释涉及到分配给text变量的内存空间,实际上任何变量都是这样。
    * 只声明一个简单变量类型,并不会引起其他的变化。只有在给变量赋值后,这个值才占用一块内存空间。
    * 如果这种占据内存空间的行为在循环中发生,该值实际上定义为一个局部值,在循环的外部会超出了其作用域。
    * 即使变量本身没有局部化到循环上,循环所包含的值也局部化到该循环上。
    * 但是,在循环外部赋值可以确保该值是主体代码的局部值,在循环内部它仍处于其作用域中。
    * 这意味着变量在退出主体代码块之前是没有超出作用域的,所以可以在循环外部访问它的值。
    这种说法勉强可以接受吧。但是Test1()中出了块仍可以正常访问,个人推测:循环的块和普通的块可能不完全一样。

    第二个,使用try块时:

     1 static void Main(string[] args)
     2         {
     3 #if 初始化text
     4             string text = null;     // 声明并初始化(单步执行的时候会执行)
     5             try
     6             {
     7                 text = "Hello!";
     8             }
     9             catch (Exception)
    10             {
    11             }
    12             finally
    13             {
    14                 Console.WriteLine("Finally1: {0}", text);    // 可以正常访问
    15             }
    16             Console.WriteLine("END1: {0}", text);            // 可以正常访问
    17 #else
    18             string text;        // 仅声明而不初始化(单步执行的时候会跳过),虽在try块中赋值,但出了try块不一定能使用
    19             try
    20             {
    21                 text = "Hello!";
    22                 //return;       // 实测没作用
    23             }
    24             catch (Exception)
    25             {
    26                 return;         // return究竟起了什么作用使得text可以访问了?
    27             }
    28             finally
    29             {
    30                 //Console.WriteLine("Finally2: {0}", text);    // 出错:使用了未赋值的局部变量
    31                 //return;       // error CS0157: 控制不能离开finally子句主体
    32             }
    33             Console.WriteLine("END2: {0}", text);    // 如果没有catch中的return,这儿出错:使用了未赋值的局部变量
    34 #endif
    35         }

    和上例一样,但是偶然在catch块中添加了return语句后,出了块可以正常访问了,这是怎么回事。看来想要解开这个谜,恐怕得深入底层了。可惜现在还不了解,如果高手路过,请不吝赐教。

  • 相关阅读:
    shell脚本--php执行普通shell命令
    shell脚本--eval执行shell命令
    shell脚本--CGI获取请求数据(GET / POST)
    shell脚本--编写CGI代码(shell结合html)以及环境变量
    shell脚本--初识CGI
    数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
    写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
    输入一个正整数,按照从小到大的顺序输出它的所有质数的因子(如180的质数因子为2 2 3 3 5 )
    写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串。(多组同时输入 )
    字符串分隔 ->连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组; •长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
  • 原文地址:https://www.cnblogs.com/chengyb/p/13913806.html
Copyright © 2011-2022 走看看