现在的位置: 首页 > 综合 > 正文

【原创】理解C#的引用类型的值传递

2012年09月12日 ⁄ 综合 ⁄ 共 1321字 ⁄ 字号 评论关闭

C#中,数据传递的方式有两种:按值传递和按引用传递,且默认情况下都是按值传递。而CLR支持两种基本类型为:值类型和引用类型。

1. 当传递的参数为值类型,且数据传递方式为按值传递时,传递的是数据的一个拷贝。

2. 当数据传递方式为按引用传递时,必须以ref或者out关键字来修饰。由于这部分不是本文主题,不做详细介绍,想了解相关内容可参见【原创】C#中ref和out的异同

3. 当引用类型参数按值传递时,传递的是引用类型地址的数据拷贝。

下面通过例子来验证第3点中所说

先看以下示例代码:

class Program
{
public static void Main()
{
var abf
= new ArgsByRef();
var abf1
= abf;
AddRef(abf);
Console.WriteLine(abf.i);
ReplaceRef(abf1);
Console.WriteLine(abf.i);
Console.WriteLine(abf1.i);
}

private static void AddRef(ArgsByRef abf)
{
abf.i
= 20;
Console.WriteLine(abf.i);
}

private static void ReplaceRef(ArgsByRef abf)
{
if (abf == null) throw new ArgumentNullException("abf");
var m
= new ArgsByRef();
abf
= m;
Console.WriteLine(abf.i);
}
}

public class ArgsByRef
{
public int i = 10;
}

现在开始来详细分析以上代码:

1. var abf = new ArgsByRef(); 语句创建一个ArgsByRef实例abf,假设abf实例指向的堆中地址为0x1323。如图:

2. var abf1 = abf; 语句创建一个ArgsByRef实例abf1,并将abf1实例的引用地址指向abf实例的引用地址,即abf1实例同样指向地址0x1323。

3.

AddRef(abf);
private static void AddRef(ArgsByRef abf)
{
abf.i
= 20;
Console.WriteLine(abf.i);
}

执行AddRef方法时,传递abf实例作为参数。由于传递的是对象的引用,所以在方法内对对象的修改会直接影响对象。如图:

4. 当执行ReplaceRef方法时,传递abf1实例作为参数,创建ArgsByRef实例m,假设实例m指向的堆地址为0x1345。如图:

5. 当执行abf=m时,其实是创建了一个abf1实例引用地址的拷贝,使当前abf1实例的引用地址为0x1345。这里重点在于引用地址的拷贝,我画的表示图如下(不知道对与不对,还望大哥们多指点一下):

6. 退出ReplaceRef方法,回到主方法后,由于是引用类型的引用地址的值传递,所以并没有改变对象的引用地址。实例abf1的引用地址仍为0x1323。

所以abf1.i仍为20

最后:说了这么多,也不知道描述清楚没有,如果有错误,还希望各位看官能不吝指点。我认为重点理解引用地址的拷贝。希望对大家理解值类型和引用类型,以及按值传递和按引用传递有帮助。

抱歉!评论已关闭.