导航

C#中,引用变量和数值变量的区别

Posted on 2008-03-15 02:01  madduck  阅读(2118)  评论(4编辑  收藏  举报
原文:http://web.newsfan.net/showthread.php?p=2105379
msdn上的正解:
The ref keyword causes arguments to be passed by reference. The effect is
that any changes made to the parameter in the method will be reflected in
that variable when control passes back to the calling method. To use a ref
parameter, both the method definition and the calling method must explicitly
use the ref keyword.

An argument passed to a ref parameter must first be initialized. This
differs from out, whose argument need not be explicitly initialized before
being passed.

大意是:ref关键字导致参数按照引用传递。结果是对于方法的参数所做的任何的改
变,都会反应到调用方法时传递的变量上。如果要方法中带有ref参数,那么调用方法
时相应参数的前面也必须加上ref关键字。比如:
class RefExample
{
static void Method(ref int i)
{
i = 44;
}
static void Main()
{
int val = 0;
Method(ref val);
// val is now 44
}
}
与另外一个导致引用参数传递的关键字out有所不同的是,ref关键字要求传递的变量必
须要初始化。out关键字则没有这项规定。

在C#中主要存在两大类型的数据:引用类型(class)和值类型(struct);对于值类型,
如你所述,跟C++中的机制是一样的(因为
C++中的class也是值类型)但对于引用类型,如果不使用ref,则是对对象的引用进行值
传递,并不进行对象的复制,但由于传递的是对象的引用,所以可以对对象的状态进行
更改;但是对于引用对象的变量则不能改变:
madduck:下面的例子举得有问题。Student s有属性name,说明s是对象。而对象是引用型的,而不是数值型的参数。所以不能说明问题。
private void button5_Click(object sender, System.EventArgs e)
{
Student s = new Student();
s.Name = "Tom";
reftest(s); //完成后s的Name是"Jerry";
}

private void reftest(Student s)
{
s.Name = "Jerry";
s = new Student(); //对于调用者的s变量无效。
s.Name = "Snoopy";
}

如果使用了ref关键字,是对对象的引用进行引用传递,就可以在被调用的方法中直接
影响到传递的变量的值了:
private void button5_Click(object sender, System.EventArgs e)
{
Student s = new Student();
s.Name = "Tom";
reftest(ref s); //调用完成后,s的Name是"snoopy";
}

private void reftest(ref Student s)
{
s.Name = "Jerry";
s = new Student();
s.Name = "Snoopy"; //影响调用者的变量值。
}


===============================================================
分界线
=================================================
原文:http://hi.baidu.com/goodjc2005/blog/item/1ca43254c28c5350574e0008.html
===============================================================

11.2.1 值参数

当利用值向方法传递参数时,编译程序给实参的值做一份拷贝,并且将此拷贝传递给该方法。被调用的方法不传经修改内存中实参的值,所以使用值参数时,可以保证实际值是安全的。在调用方法时,如果形式化参数的类型是值参数的话,调用的实参的值必须保证是正确的值表达式。在下面的例子中,程序员并没有实现他希望交换值的目的:

程序清单11-2:

using System;
class Test
{
static void Swap(int x,int y){
int temp=x;
x=y;
y=temp;
}
static void Main(){
int i=1,j=2;
Swap(i,j);
Console.WriteLine("i={0},j={1}",i,j);
}
}

编译上述代码,程序将输出:

i=1,j=2

11.2.2 引用型参数

和值参不同的是,引用型参数并不开辟新的内存区域。当利用引用型参数向方法传递形参时,编译程序将把实际值在内存中的地址传递给方法。

在方法中,引用型参数通常已经初始化。再看下面的例子。本文发表于www.bianceng.cn(编程入门网)

程序清单11-3:

using System;
class Test
{
static void Swap(ref int x,ref int y){
int temp=x;
x=y;
y=temp;
}
static void Main(){
int i=1,j=2;
Swap(ref i,ref j);
Console.WriteLine("i={0},j={1}",i,j);
}
}

编译上述代码,程序将输出:

i=2,j=1

Main函数中调用了Swap函数,x代表i,y代表j。这样,调用成功地实现了i和j的值交换。

在方法中使用引用型参数,会经常可能导致多个变量名指向同一处内存地址。见示例:

class A
{
string s;
void F(ref string a,ref string b){
s="One";
a="Two";
b="Three";
}
void G(){
F(ref s,ref s);
}
}

在方法G对F的调用过程中,s的引用被同时传递给了a和b。此时,s,a,b同时指向了同一块内存区域。