老生常谈C#中的 ref 与 out
在C#中,定义函数时,函数的参数有两种形式,分别是引用参数和值参数。
如果使用“值参数”,也就是说,我们给函数参数所使用的变量赋一个值,例如:
//定义一个函数
Public static void ValueTest(string var)
{
Var = Var + "在末尾加点东西"; //这个函数的作用就是在Var的末尾加上"在末尾加点东西"
Console.WriteLine("经过函数修改后的值:{0}",Var);
}
//调用此函数时,给参数var赋值,让var等于ValueStr的值
Public static void
{
string ValueStr = "初始化一个字符串";
Console.writeLine("原来的值:{0}",ValueStr);
ValueTest(ValueStr);
Console.WriteLine("让我们来看看到底有没有改变ValueStr 的值:{0}",ValueStr);
}
//显示结果是:
原来的值:初始化一个字符串;
经过函数修改后的值:初始化一个字符串在末尾加点东西;
让我们来看看到底有没有改变ValueStr 的值: 初始化一个字符串;
结果显示,ValueStr的值没有改变,所以说通过值参数不能改变原变量的值,但有时我们确实想在函数中改变变量的值,那么我们就需要引用传递参数。
即函数所处理的变量与函数所调用的变量是相同的,因此在函数中对这个变量进行修改,那么就等于真正的修改了此变量,为此,只需要使用ref来指定参数,我们来对上例进行一下修改,例如:
public static void ValueTest(ref string var) //注意在形式参数里添加了ref关键字
{
Var = Var + "在末尾加点东西"; //这个函数的作用就是在Var的末尾加上"在末尾加点东西"
Console.WriteLine("经过函数修改后的值:{0}",Var);
}
//调用此函数时,给参数var赋值,让var等于ValueStr的值
Public static void
{
string ValueStr = "初始化一个字符串";
Console.writeLine("原来的值:{0}",ValueStr);
ValueTest( ref ValueStr); //注意在调用函数时,必须在实参中指定ref
Console.WriteLine("让我们来看看到底有没有改变ValueStr 的值:{0}",ValueStr);
}
//显示结果是:
原来的值:初始化一个字符串;
经过函数修改后的值:初始化一个字符串在末尾加点东西;
让我们来看看到底有没有改变ValueStr 的值: 初始化一个字符串在末尾加点东西;
结果显示ValueStr值被改变。在使用ref的时候我们要注意,调用变量之前,一定要给这个变量初始化,例如:
string ValueStr;
ValueTest( ref ValueStr); //这样是非法的。
还有一点要注意的是:我们使用ref的目的是用来修改变量的值,如果我们不能在函数中修改用ref 引用的参数变量,那么程序也是非法的。
例如:
Const string ValueStr = "初始化一个字符串";
ValueTest( ref ValueStr); //这样是非法的。
下面来说一下out,out也称为输出参数,out与ref关键字的使用方式相同(在函数定义和调用函数时,都必须用作参数的修饰符)。实际上,它们两个的作用也完全一样,都能够修改调用中使用的变量的值。
但是out与ref 有一些区别:
- 使用ref时,被用作参数的变量必须提前初始化,而使用out,则不需要,只需要要声明就可以。
- 使用out时,被用作参数的变量,即使提前初始化,在函数内使用该变量时,也会被当作未赋值。也就是说把此变量的值自动丢失处理。
下面我们来看一个使用out的例子:返回数组中的最大值,获取数组中最大值的元素下标。
Static void MaxValue(int[] iVar, out int indexMax)
{
Int MaxV = iVar[0];
For(int i = 1; i < iVar.length; i++)
{
If(MaxV < iVar[i])
{
MaxV = iVar[i];
indexMax = i;
}
}
return MaxV;
}
//调用此函数
Int[] myArray = {1,3,4,2,6,7,9,8};
Int indexMax;
Console.WriteLine("数组中最大值是:{0}",MaxValue(myArray,out indexMax)); //调用函数时,必须要加上out关键字
Console.WriteLine("数组中最大值的坐标是:{0}",indexMax);
显示结果:
数组中最大值是:9;
数组中最大值的坐标是:6;
从这个实例我们可以看出使用out后, indexMax的值被改变了。
关于ref 与 out我的理解是:函数定义时,加上这个两个关键字的其中之一后,就告诉编译器,这个参数名(例如:(ref string var)中的var)与所调用的实际变量(例如: string ValueStr = "初始化一个字符串"中的ValueStr;)指向同一个内存区域,而这个内存区域存储的就是"初始化一个字符串"这个值,也可以理解为var 与 ValueStr的内存地址是相同的,所以修改var,就是修改var所指向的值,而var 与 ValueStr指向同一个内存区域,所以也就相同于修改了ValueStr。
不知道这样理解对不对,请大虾们多多指点。