【整理】引用类型与ref传递实例精解

一直以来对于在引用类型前加ref传递变量和不加ref传递引用类型变量的区别不是很清楚,最近看到网上一个朋友给的一道题,仔细思索和编写代码测试,终于明白其中区别了。现整理如下,以供自己和朋友们理解和记忆。

ref是使变量通过引用的方式传递,而引用类型本身也是通过引用方式传递变量,所以一直纠结在这两者的区别?经过思考、查证资料以及编写代码证实,两者的区别在于:

引用类型前不加ref时,只能修改所引用对象的值,而不能对所引用对象的引用进行更改。

而在引用类型前加ref时,不仅可以修改所引用对象的值,也可以改变对所引用对象的引用。

通过下面测试代码,能够很好的反映出来。代码中使用了非安全代码(指针),通过使用指针显示对象的内存地址,可以观察出对对象引用的变化。

不加ref传递:

 
  
1 class Value
2 {
3 public int i = 15 ;
4 }
5 class Program
6 {
7 static unsafe void Main( string [] args)
8 {
9 Program t = new Program();
10 t.first();
11 }
12 public unsafe void first()
13 {
14 int i = 5 ;
15 Value v = new Value();
16 v.i = 25 ;
17
18 /// 查看V实例的地址
19   fixed ( int * pi = & (v.i))
20 {
21 Console.WriteLine( " V.i Address 0x{0:X} " , ( int )pi);
22 }
23
24 second(v, i);
25
26 /// 执行完second函数后V实例的地址
27 fixed ( int * pi = & (v.i))
28 {
29 Console.WriteLine( " V.i Address 0x{0:X} " , ( int )pi);
30 }
31
32 Console.WriteLine(v.i);
33 }
34 public unsafe void second(Value v, int i)
35 {
36 i = 0 ;
37 v.i = 20 ;
38
39 /// 重新指定前V实例的地址
40 fixed ( int * pi = & (v.i))
41 {
42 Console.WriteLine( " V.i Address 0x{0:X} " , ( int )pi);
43 }
44
45 Value val = new Value();
46 v = val; /// 创建一个v的副本,指向val,因此v的值不会被val改变
47
48 /// val实例的地址
49 fixed ( int * pi = & (val.i))
50 {
51 Console.WriteLine( " val.i Address 0x{0:X} " , ( int )pi);
52 }
53
54 /// v的副本地址
55 fixed ( int * pi = & (v.i))
56 {
57 Console.WriteLine( " V.i Address 0x{0:X} " , ( int )pi);
58 }
59 Console.WriteLine(v.i + " " + i + " " ); // 15,0 可以理解
60 }
61 }

运行结果如下:

2010051615080656.jpg

在这里,由于不能改变对V引用对象的引用,因此在执行“V=Val”时,其实是创建了一个V对象的副本对象,然后将副本对象的引用指向Val对象。

 

加ref传递:

 
   
class Value
{
public int i = 15 ;
}
class Program
{
static unsafe void Main( string [] args)
{
Program t
= new Program();
t.first();
}
public unsafe void first()
{
int i = 5 ;
Value v
= new Value();
v.i
= 25 ;

/// 查看V实例的地址
fixed ( int * pi = & (v.i))
{
Console.WriteLine(
" V.i Address 0x{0:X} " , ( int )pi);
}

second(
ref v, i);

/// 执行完second函数后V实例的地址
fixed ( int * pi = & (v.i))
{
Console.WriteLine(
" V.i Address 0x{0:X} " , ( int )pi);
}

Console.WriteLine(v.i);
}
public unsafe void second( ref Value v, int i)
{
i
= 0 ;
v.i
= 20 ;

/// 重新指定前V实例的地址
fixed ( int * pi = & (v.i))
{
Console.WriteLine(
" V.i Address 0x{0:X} " , ( int )pi);
}

Value val
= new Value();
v
= val; /// v直接指向val,v断开了与之前连接

/// val实例的地址
fixed ( int * pi = & (val.i))
{
Console.WriteLine(
" val.i Address 0x{0:X} " , ( int )pi);
}

/// v的地址
fixed ( int * pi = & (v.i))
{
Console.WriteLine(
" V.i Address 0x{0:X} " , ( int )pi);
}
Console.WriteLine(v.i
+ " " + i + " " ); // 15,0 可以理解
}
}

运行结果如下:

2010051615131215.jpg

在这里的话,由于加了ref传递对象V,因此在执行“V=Val”时,V对象直接指向了Val对象,因此V对象的地址不再0x12D16A4,而是Val的地址0x12D36CC。

转载于:https://www.cnblogs.com/zwffff/archive/2010/05/16/1736778.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值