C#阶段提高之---交换数值

       最近在从事两年前学过的C#语言工作,对于第三门接触的编程语言(第一门当然是是C语言、第二门是汇编),好多知识随时间的流过都变得不是那么熟练,刚好趁此机会学习巩固基础,厚积薄发。在此记下笔记也是想C#入门的同学参考,怎样在.NET的道路上更上一层楼。

首先就从简单的非基础的基础开始(一定要有语言的基本功底,比如:变量、函数、运算符、类、对象等等)。

我们先来做一个例子:交换两个数字的值。看一下代码:

   1:   public void Swap(int a, int b)
   2:          {
   3:              Console.WriteLine("交换前的两个值分别是:a={0},b={1}",a,b);
   4:              int temp;
   5:              temp = a;
   6:              a=b;
   7:              b = temp;
   8:              Console.WriteLine("交换后的两个值分别是:a={0},b={1}",a,b);
   9:          }

这是典型的按照值类型的交换,在交换过程前加入有两个数字num1=1、num2=2,调用此函数在函数内部实现交换绝对是没有问题的,也可以实现交换的输出。但是外部的num1,num2真的实现了交换吗?我们来分析一下,如果我来调用Swap(num1,num2),两个实参传入方法,形参a、b接受参数,对应的a=1,b=2,在函数内部交换的值只是形参(实参的数值的一个复制,不会对实参产生影响),所以再出的交换对num1,num2不会产生影响。一句话,这就是按值传递!按值传递只能将数据带入构造函数,不能带出构造函数,因此num1,num2不会发生变化。

那么怎样实现真正的交换数值呢?答曰:引用传递!按引用传递时将数值的地址传递过去,同时执行一个地址,一次修改一个,另一个也会发生变化!在C#中我们通常借用ref,out实现这类情况!

例如代码:

   1:  static void Main(string[] args)
   2:          {
   3:              int num1 = 1;
   4:              int num2 = 2;
   5:              Console.WriteLine("a={0},b={1}",num1,num2);
   6:              Swap(ref num1,ref num2);
   7:              Console.WriteLine("a={0},b={1}", num1, num2);
   8:   
   9:          }
  10:          public static void Swap( ref int a,ref int b)
  11:          {
  12:              int temp;
  13:              temp = a;
  14:              a = b;
  15:              b = temp;
  16:          }
 
这样就会交换成功!

 

为什么会这样呢?ref的作用是什么呢?ref 关键字使参数按引用传递。 其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。通俗的讲按引用传递时既可以将参数带入方法,亦可以将参数值带出方法。对同一个地址的数值修改肯定会影响变量的值,因此改变,交换成功!

注意:

请不要将“通过引用传递”概念与“引用类型”概念相混淆。这两个概念不相关;方法参数无论是值类型还是引用类型,都可通过 ref 进行修饰。 因此,通过引用传递值类型时没有值类型装箱。

那么什么是Out呢?请看这个例子:

   1:  class Class1
   2:  {
   3:      static void Method(out int i)
   4:      {
   5:          i = 44;
   6:      }
   7:      static void Main()
   8:      {
   9:          int value;
  10:          Method(out value);
  11:          // value=44
  12:      }
  13:  }
尽管作为 out 参数传递的变量不必在传递之前进行初始化,但被调用的方法需要在返回之前赋一个值。

尽管 ref 和 out 关键字会导致不同的运行时行为,但在编译时并不会将它们视为方法签名的一部分。 因此,如果两个方法唯一的区别是:一个接受 ref 参数,另一个接受 out 参数,则无法重载这两个方法。

传值传递引用的主要区别实质是对地址的使用,按引用传递是赋值一个副本,而按引用传递时则是对地址的传递,直接修改原始。

那么对引用类型量传递时间会涉及此类问题吗?我认为是不会的,下面我们会通过一个例子来演示这个结论。首先我先说出这个结论:引用类型的变量传递是按引用传递的,直接对地址操作!(数组类型是引用类型),下面我们来操作一个数组:

   1:   static void FillArray(ref int[] arr)
   2:          {
   3:              if (arr==null)
   4:              {
   5:                  arr = new int[10];
   6:              }
   7:              arr[0] = 1111;
   8:              arr[2] = 2345;
   9:          }
  10:          static void Main(string[] args)
  11:          {
  12:              int[] arr = new int[10] { 1,2,3,4,5,6,7,8,9,0};
  13:              FillArray(ref arr);
  14:              string s = "";
  15:              foreach (var a in arr)
  16:              {
  17:                  s+= a+"\t";
  18:              }
  19:              Console.WriteLine(s);
  20:          }

输出结果是已经修改过的数组:

 

1111    2       2345    4       5       6       7       8       9       0

下面我们直接不适用ref来传递数组:

   1:  //注意不适用ref关键字 
   2:  static void FillArray( int[] arr)
   3:          {
   4:              if (arr==null)
   5:              {
   6:                  arr = new int[10];
   7:              }
   8:              arr[0] = 1111;
   9:              arr[2] = 2345;
  10:          }
  11:          static void Main(string[] args)
  12:          {
  13:              int[] arr = new int[10] { 1,2,3,4,5,6,7,8,9,0};
  14:              FillArray( arr);
  15:              string s = "";
  16:              foreach (var a in arr)
  17:              {
  18:                  s+= a+"\t";
  19:              }
  20:              Console.WriteLine(s);
  21:          }
 
得到的结果依旧是:

1111       2       2345       4       5        6      7        8         9        0

 

(【数组是按引用传递的,所以用不用ref是一样的..                         】)这样子理解是错误的,稍后会解释这是为什么。关于值类型,引用类型,按值传递,按引用传递是怎么运行的,有什么关系 后文给出明确的解释,在此记录作为学习记录。

posted @ 2012-04-30 21:47  这里显示的是昵称  阅读(1118)  评论(2编辑  收藏  举报
新浪微博