.Net 框架程序设计(4)

1 值传递和引用传递

值传递是传递的值的拷贝;引用传递是传递的对象本身。

测试代码:

classProgram
    {
        staticvoid Main(string[] args)
        {
            SomeValueType valueParam;
            SomeRefType refParam = new SomeRefType();
            //*****    <1>    ****
            valueParam.Name = "before excute";
            Console.WriteLine("值类型作参数,执行前:{0}", valueParam.Name);
            Test.DoSomething(valueParam);
            Console.WriteLine("值类型作参数,执行后:{0}", valueParam.Name);
            Console.WriteLine(""); 
            //*****    <2>    ****
            refParam.Name = "before excute";
            Console.WriteLine("引用类型作参数,执行前:{0}", refParam.Name);
            Test.DoSomething(refParam);
            Console.WriteLine("引用类型作参数,执行后:{0}", refParam.Name);
            Console.WriteLine(""); 
            //*****    <3>    ****
            valueParam.Name = "before excute";
            Console.WriteLine("值类型作参数,执行前:{0}", valueParam.Name);
            Test.DoOtherSomething(valueParam);
            Console.WriteLine("值类型作参数,执行后:{0}", valueParam.Name);
            Console.WriteLine(""); 
            //*****    <4>    ****
            refParam.Name = "before excute";
            Console.WriteLine("引用类型作参数,执行前:{0}", refParam.Name);
            Test.DoOtherSomething(refParam);
            Console.WriteLine("引用类型作参数,执行后:{0}", refParam.Name);
            Console.WriteLine(""); 
            //*****    <5>    ****
            valueParam.Name = "before excute";
            Console.WriteLine("值类型引用传递,执行前:{0}", valueParam.Name);
            Test.DoSomething(ref valueParam);
            Console.WriteLine("值类型引用传递,执行后:{0}", valueParam.Name);
            Console.WriteLine(""); 
            //*****    <6>    ****
            refParam.Name = "before excute";
            Console.WriteLine("引用类型引用传递,执行前:{0}", refParam.Name);
            Test.DoSomething(ref refParam);
            Console.WriteLine("引用类型引用传递,执行后:{0}", refParam.Name);
            Console.WriteLine(""); 
            //*****    <7>    ****
            valueParam.Name = "before excute";
            Console.WriteLine("值类型引用传递,执行前:{0}", valueParam.Name);
            Test.DoOtherSomething(ref valueParam);
            Console.WriteLine("值类型引用传递,执行后:{0}", valueParam.Name);
            Console.WriteLine(""); 
            //*****    <8>    ****
            refParam.Name = "before excute";
            Console.WriteLine("引用类型引用传递,执行前:{0}", refParam.Name);
            Test.DoOtherSomething(ref refParam);
            Console.WriteLine("引用类型引用传递,执行后:{0}", refParam.Name);
            Console.WriteLine(""); 
            Console.ReadKey();
        }
    }  
    classSomeRefType
    {
        publicstring Name;
    } 
    structSomeValueType
    {
        publicstring Name;
    } 
    classTest
    {
        publicstaticvoid DoSomething(SomeValueType v)
        {
            v.Name = "value type param";
            Console.WriteLine("值类型作参数,执行中:"+v.Name);
        } 
        publicstaticvoid DoSomething(SomeRefType r)
        {
            r.Name = "ref type param";
            Console.WriteLine("引用类型作参数,执行中:" + r.Name);
        } 
        publicstaticvoid DoOtherSomething(SomeValueType v)
        {
            v = new SomeValueType();
            v.Name = "change value type param";
            Console.WriteLine("引用类型作参数,执行中:" + v.Name);
        } 
        publicstaticvoid DoOtherSomething(SomeRefType r)
        {
            r = new SomeRefType();
            r.Name = "change ref type param";
            Console.WriteLine("引用类型作参数,函数内创建对象,执行中:" + r.Name);
        } 
        publicstaticvoid DoSomething(refSomeValueType v)
        {
            v.Name = "value type param with ref";
            Console.WriteLine("引用传递值类型,执行中:" + v.Name);
        } 

        publicstaticvoid DoSomething(refSomeRefType r)
        {
            r.Name = "ref type param with ref";
            Console.WriteLine("引用传递引用类型,执行中:" + r.Name);
        } 
        publicstaticvoid DoOtherSomething(refSomeValueType v)
        {
            v = new SomeValueType();
            v.Name = "create value type param with ref ";
            Console.WriteLine("引用传递值类型,函数内建对象,执行中:" + v.Name);
        } 
        publicstaticvoid DoOtherSomething(refSomeRefType r)
        {
            r = new SomeRefType();
            r.Name = "create ref type param with ref";
            Console.WriteLine("引用传递引用类型,函数内创建对象,执行中:" + r.Name);
        }
    } 


 

2 代码分析

2.1 值参数<1>

    从运行后的结果来看,值类型参数在传递进函数前后没有任何变化,也就是说对形参的修改没有影响实参。

从内存分配上看,值类型参数分配在线程栈上,形参是对实参的完全拷贝。实参和形参都有各自的地址空间,两者间没有任何关联。

2.2 引用参数<2><4>

    从运行后的结果来看,引用类型参数在传递进函数前后发生了变化,也就是说对形参的修改直接影响了实参的值。

    从内存分配上看,引用类型参数分配在托管堆上,而保持这个对象的引用存放在线程栈上。因为实参保存的是该对象在托管堆中的地址,所以传给形参的也是这个地址,这样形参和实参都保存了相同的地址引用,他们同时指向了同一个对象地址,在函数内部如果vp不创建对象,对形参的修改会直接反映到实参上。

如果在函数内部形参rp又创建了新的对象,则内存分配如下:

从上图可以看出rp指向了另一个创建的对象,形参和实参没有了关联,此时再次对形参进行修改,修改不会影响到实参。

2.3 值类型引用传递

  

从运行后的结果来看,值类型参数在传递进函数前后发生了变化,也就是说对形参的修改直接影响了实参的值。

从内存分配上看,传给形参的是实参在线程堆栈上的地址,形参指向的其实仍然是实参所在的位置,两者完全同步。

2.4 引用类型引用传递<6><8>

   从运行后的结果来看,引用类型参数在传递进函数前后发生了变化,也就是说对形参的修改直接影响了实参的值。

 

 

 

 

从内存分配上看,和值类型的引用传递在堆栈上的形式有一定的相似,形参保存的是实参的地址,形参并没有指向对象在托管堆上的地址,而是指向了实参,和实参共同拥有一个指向该对象内存中的引用。

如果在函数内部形参rp又创建了新的对象,则内存分配如下:

和<2><4>对照比较,在加上ref后,实参和形参自始至终都具有相同的引用。 

 

总结:1)值传递是对目标对象的值拷贝(无论是值类型和引用类型对象,引用类型的值拷贝是拷贝的对象在托管堆中的地址)。

      2)引用传递是传递的目标对象本身,才是真正的引用传递(相对于引用类型传递)。 

最终的运行结果全图如下: 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值