读书人

.Net 框架程序设计(四)

发布时间: 2012-12-17 09:31:40 作者: rapoo

.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>.Net 框架程序设计(四)

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

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

.Net 框架程序设计(四)2.2 引用参数<2><4>.Net 框架程序设计(四)

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

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

.Net 框架程序设计(四)

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

.Net 框架程序设计(四)

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

2.3 值类型引用传递 .Net 框架程序设计(四)

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

.Net 框架程序设计(四)

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

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

.Net 框架程序设计(四)

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

.Net 框架程序设计(四)

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

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

.Net 框架程序设计(四)

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

总结:1)值传递是对目标对象的值拷贝(无论是值类型和引用类型对象,引用类型的值拷贝是拷贝的对象在托管堆中的地址)。 2)引用传递是传递的目标对象本身,才是真正的引用传递(相对于引用类型传递)。 最终的运行结果全图如下: .Net 框架程序设计(四)

读书人网 >软件架构设计

热点推荐