C#中的ref与out关键字

上一次随笔中提到有winform程序有两个知识点挺重要点,第一个是TryParse方法和Parse方法区别,这一次来谈谈另一个学习心得,就是C#中的关键字out与ref

View Code
 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Windows.Forms;
9
10 namespace WindowsFormsTest
11 {
12 public partial class Form1 : Form
13 {
14 public Form1()
15 {
16 InitializeComponent();
17 }
18
19 private void btnCompute_Click(object sender, EventArgs e)
20 {
21 string firstNum = txtFirstNum.Text;
22 string secondNum = txtSecNum.Text;
23 int i1, i2;
24
25 if (int.TryParse(firstNum, out i1) == false)
26 {
27 MessageBox.Show("第一个数不是合法的整数");
28 return;
29 }
30 if (int.TryParse(secondNum, out i2) == false)
31 {
32 MessageBox.Show("第二个数不是合法的整数");
33 return;
34 }
35
36 int result = i1 + i2;
37 txtResult.Text = Convert.ToString(result);
38 }
39 }
40 }

以前也没怎么注意这两个关键字,今天学到了它们,就必须把它们搞明白。发现visual C# 2008大学教程上有讲这两个关键字,我做了一下笔记希望对大家有用。

我们先来看一下这两个keyword的说明。

许多编程语言中调用函数的两种方法是按值调用(call-by-value)和按引用调用(call-by-reference)。参数按值调用(C#默认)传递时,生成参数值副本并传给被调用函数。副本的改变并不影响调用者的原始变量值,这样就可以防止意外的副作用影响开发正确、可靠的软件系统。按引用调用时、调用者让被调用函数能够直接访问调用者的数据,并允许被调用函数能够修改其中的数据。按引用调用的安全性较差,因为被调用函数能够直接访问和修改调用者的数据。

如果要按引用传递一个变量,使被调方法可以修改变量值,该怎么办呢?为此,C#提供了关键字ref与out。参数声明中使用关键字ref可以按引用将变量传递给方法-被调方法可以修改调用者的原变量。ref关键字用于调用方法中已经初始化的变量。通常,调用方法包含未初始化变量变元时,编译器产生一个错误。在参数前面加上关键字out可以建立输出参数,告诉编译器这个变元按引用传入被调方法,被调用方法对调用者的原变量赋值。如果方法中没有在每个执行路径上对输出参数赋值,则编译器产生一个错误。这样就使编译器不会对传入方法的未初始化变量变元产生错误消息。一个方法只能通过return语句向调用者返回一个值,但指定多个输出参数(ref或out)可以返回多个值。

也可以按引用传递引用型变量,从而修改传递的引用型变量,使用引用新对象。按引用传递引用句是个复杂的技术。

下面的例子用关键字ref与out操纵整数值。RefAndOutKeyword类包含三个方法,计算整数的平方。方法SquareRef将参数x自乘,将新值赋予x。SquareRef方法的参数x声明为ref int,表示传入这个方法的变元应为按引用传递的整数。由于变元按引用传递,因此第39行赋值时修改调用者的原变元值。

SquareOut方法将参数赋值为6,然后求这个值的平方。SquareOut的参数声明为out int,表示传入这个方法的变元应为按引用传递的整数,变元不必事先初始化。

Square方法将参数x自乘,将新值赋予x。调用这个方法时,变元的副本传入参数x。这样,即使方法中修改参数x,调用者的原值也不会修改。

 

 

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace ConsoleApplication1
7 {
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 RefAndOutKeyword test = new RefAndOutKeyword();
13 test.DemonstrateRefAndOutKeyword();
14 Console.ReadKey();
15 }
16 }
17 class RefAndOutKeyword
18 {
19 public void DemonstrateRefAndOutKeyword()
20 {
21 int y = 5;//初始化变量y为5
22 int z;//声明变量z但不初始化z
23
24 //先显示y和z的原始值
25 Console.WriteLine("y的原始值是:{0}", y);
26 Console.WriteLine("z的原始值是:未初始化\n");
27
28 //传递y和z的引用
29 SquareRef(ref y);//这里必须使用关键字ref
30 SquareOut(out z);//这里必须使用关键字out
31
32 //y和z的值分别被方法SquareRef、SquareOut修改之后显示y和z的值
33 Console.WriteLine("调用方法SquareRef之后y的值是:{0}", y);
34 Console.WriteLine("调用方法SquareOut之后z的值是:{0}\n", z);
35
36 //传递y和z的副本
37 Square(y);
38 Square(z);
39
40 //当将y和z的副本被函数Square调用之用显示它们的值并没有被修改
41 Console.WriteLine("调用方法Square之后y的值是:{0}", y);
42 Console.WriteLine("调用方法Square之后z的值是:{0}\n", z);
43
44 }
45
46 private void Square(int x)
47 {
48 x = x * x;//将传入的实参的副本平方
49 }
50
51 private void SquareOut(out int x)
52 {
53 x = 6;//给调用者的参数x赋值为6
54 x = x * x;//将调用者的参数x进行平方运算
55 }
56
57 private void SquareRef(ref int x)
58 {
59 x = x * x;//将调用者的参数x进行平方运算
60 }
61
62
63 }
64 }

方法DemonstrateRefAndOutKeyword(第19-44行)调用SquareRef、SquareOut与Square方法,这个方法首先将变量y初始化为5,声明但不初始化变量z。第29-30行调用SquareRef和SquareOut方法,注意变量传入带引用参数的方法时,变元前面要加上声明引用参数时所用的关键字(ref或out)。第33-34行显示调用SquareRef和SquareOut方法之后的y值和z值。注意y变成25,z设置成36。

第37-38行用y、z变元调用Square方法。这里,两个变元都按值传递---只将其数值副本传入Square方法,结果,y、z值仍然保持25和36。第41-42行输出y、z值,显示其没有修改。

注意:方法调用中的out与int变元要与方法声明中指定的参数相符,否则会发生编译错误。

程序运行结果:

 

   


 

 

posted @ 2011-12-16 08:33  keepLearning...  阅读(325)  评论(1编辑  收藏  举报