.Net 框架程序设计(4)

来源:互联网 发布:介绍云计算的ppt 编辑:程序博客网 时间:2024/05/29 19:28

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)引用传递是传递的目标对象本身,才是真正的引用传递(相对于引用类型传递)。 

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

 

原创粉丝点击