• 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语句后,出了块可以正常访问了,这是怎么回事。看来想要解开这个谜,恐怕得深入底层了。可惜现在还不了解,如果高手路过,请不吝赐教。

  • 相关阅读:
    BibTex (.bib) 文件的凝视
    SQL注入原理解说,非常不错!
    怎样将文件隐藏在图片中
    白话经典算法系列之五 归并排序的实现
    帮你理解多线程
    很好的理解遗传算法的样例
    薏米红豆粥功效及做法介绍
    Linux makefile 教程 很具体,且易懂
    站点权重对于站点的重要性
    Codeforces Round #250 (Div. 2)——The Child and Set
  • 原文地址:https://www.cnblogs.com/chengyb/p/13913806.html
Copyright © 2020-2023  润新知