参数和返回值与全局数据

  本节将详细介绍如何通过全局数据以及参数和返回值与函数交换数据。首先分析下面的代码:

  1. class Program
  2. {
  3. static void ShowDouble(ref int val)
  4. {
  5. val *= 2;
  6. Console.WriteLine("val doubled = {0}", val);
  7. }
  8. static void Main(string[] args)
  9. {
  10. int val = 5;
  11. Console.WriteLine("val = {0}", val);
  12. ShowDouble(ref val);
  13. Console.WriteLine("val = {0}", val);
  14. }
  15. }
  这段代码与本章前面的代码稍有不同,在前面的示例中,在 Main() 中使用了变量名 myNumber,这说明了局部变量可以具有相同的名称,且不会相互干涉。这里列出的两个代码示例更加类似,以便我们击中精力研究它们的区别,而不必考虑变量名。

  和下面的代码比较:

  1. class Program
  2. {
  3. static int val;
  4. static void ShowDouble()
  5. {
  6. val *= 2;
  7. Console.WriteLine("val doubled = {0}", val);
  8. }
  9. static void Main(string[] args)
  10. {
  11. val = 5;
  12. Console.WriteLine("val = {0}", val);
  13. ShowDouble();
  14. Console.WriteLine("val = {0}", val);
  15. }
  16. }

  这两个 ShowDouble() 函数的结果是相同的。

  使用哪种方法并没有什么硬性规定,这两种方法都十分有效。但需要考虑一些规则。

  首先,在第一次讨论这个问题时就提到过,使用全局值的 ShowDouble() 版本只使用全局变量 val。为使用这个版本,必须使用这个全局变量。这会对该函数的灵活性有轻微的限制,如果要存储结果,就必须总是把这个全局变量值复制到其他变量中。另外,全局数据可能在应用程序的其他地方被代码修改,这会导致预料不到的结果(其值可能会改变,等我们认识到这一点时为时已晚)。

  但是,损失了这种灵活性常常是有好处的。我们有时希望把一个函数只用于一个目的,使用全局数据存储能减少在函数调用中犯错的可能性,例如给它传递错误的变量。

  当然,也可以说,这种简化实际上使代码更难理解。显式指定参数可以一眼看出发生了什么改变。如对于 FunctionName(val1, out val2) 函数调用,马上就可以知道 val1val2 都是要考虑的重要变量,在函数执行结束后,会为 val2 赋予一个新值。反之,如果这个函数不带参数,就不能对它处理了什么数据做任何假设。

  最后,记住未必总是能使用全局数据。本书后面将介绍在不同的文件中编写代码,以及不同名称空间中的代码如何通过函数彼此通信。像这样的情况,代码常常要分开编写,显然不能使用全局存储方式。

  总之,可以自由选择使用哪种技术来交换数据。一般情况下,最好使用参数,而不使用全局数据,但有时使用全局数据更合适,使用这种技术并没有错。