代码改变世界

理解参数传递

2011-05-21 11:38  littlelion  阅读(609)  评论(5编辑  收藏  举报

说起来惭愧,直到今天,我才认真专研了参数传递究竟是怎么回事,按值传递和按引用传递到底有什么区别,想想以前好读书不求甚解,什么事就那么一带而过,考试得了高分拿了奖学金就觉得万事大吉了,无形之中荒废了多少青春岁月啊,好在对于学习知识来说任何时候都不算晚,这几天我一直有一种翻然醒悟的感觉,好像生命重获新生了,呃。。。夸张了一点哈,不过我很是开心,我喜欢这种状态。

这几天一直在读《你必须知道的.NET》,收获真的不少,在这里记录一下我的阅读日记,也算是对学过的内容进行一下复习了。

参数的传递,分为以下4种方式:

值类型的按值传递

引用类型的按值传递

值类型的按引用传递

引用类型的按引用传递

刚读到这四种方式时,觉得有点绕,没关系,静下心来,结合例子深入推敲一下,就很容易理解了。

1.值类型参数的按值传递

先看例子

class Program
{
static void Main(string[] args)
{
int number2 = 5;
Function(number2);
Console.WriteLine(number2);
}
private static void Function(int number1)
{
number1
+= 1;
Console.WriteLine(number1);
}
}

输出结果为:

从输出结果来看,值类型的参数传递之后,并没有对原来的实例number2 产生影响,这是因为,从本质上来说,值类型内存分配于线程的堆栈上,它本身保存的就是实例本身,在传递时实际上传递的是实例的copy,也就是说在main函数中调用的Function方法中操作的是属于其本身的实例copy,也就是number1,因此首先输出了6,而这一操作并不会对原来的number2产生影响,因此执行最后一句时,输出的还是5,并不是6。

2.引用类型参数的按值传递

public class ValueType
{
public int number1 = 10;
}
class Program
{
static void Main(string[] args)
{
ValueType myValueType
= new ValueType();
Function(myValueType);
//引用类型的参数在传递时,传递的是引用地址的copy
Console.WriteLine(myValueType.number1);
}
private static void Function(ValueType i)
{
i.number1
= 11;
Console.WriteLine(i.number1);
}

从输出结果来看,参数传递后影响了原来的myValueType.number1,这是因为引用类型的参数按值传递传递的是参数的引用地址的copy,这里的按值传递的“值”指的就不是具体的数据了,所以会改变原来实例的地址指向,使得myValueType.number1指向了托管堆中的11,而不再是10了。

3.值类型的参数按引用传递

4.引用类型的参数按引用传递

从字面上来看,按引用传递,传递的一定是参数的地址,势必会改变原来对象的地址指向。

首先看值类型的按引用传递

class Program
{
static void Main(string[] args)
{
int number1 = 24;
TransferByValue(
ref number1);
Console.WriteLine(number1);
}
//ref:值类型按引用传递 必须初始化
private static void TransferByValue(ref int oneValue)
{
oneValue
= 23;
Console.WriteLine(oneValue);
}
}

输出结果:

从输出结果来看,按引用传递改变了原来对象的地址指向,number1的地址指向了23,也就是说,传递的是参数的地址,并不是参数的本身。

再来看引用类型参数的按引用传递

public class oneStr
{
public string str1 = "first";
}
class Program
{
static void Main(string[] args)
{
oneStr mystr
= new oneStr();
Function(
ref mystr.str1);
Console.WriteLine(mystr.str1);
}
private static void Function(ref string str)
{
str
= "second";
Console.WriteLine(str);
}
}

输出结果:

从输出结果来看,引用类型参数的按引用传递改变了mystr.str1的地址指向,因此输出了second,而不是first


综上所述,按值传递:当参数为值类型时,这个“值”指的是实例本身,传递和操作的是实例的copy,因此不会对原来的实例产生影响;

                              当参数为引用类型时,这个“值”指的是实例的引用,传递和操作的是实例引用的copy,会对原来的实例产生影响。

              按引用传递:当参数为值类型时,这个“引用”指的是该值类型的地址,会对原来的实例产生影响;

                               当参数为引用类型时,这个“引用”指的是对象引用的地址,会对原来的实例产生影响。


下面再来看看string的特殊,凡事总有特殊,特殊的就麻烦,不过总是千篇一律也没意思,呵呵。

先看个例子吧,string类型的参数传递

class Program
{
static void Main(string[] args)
{
string str2 = "second";
Function(str2);
Console.WriteLine(str2);
}
private static void Function(string str1)
{
str1
= "first";
Console.WriteLine(str1);
}
}

输出结果:

从输出结果上看,Function并没有对原来的str2产生影响,最后一条指令执行了之后输出的还是second。

main函数在执行过程中,调用Function方法时,具体过程为,先生成一个string对象str1,其值为“first”,把一个地址赋给str1,因此改变的是str1,而对于方法外的str2没有影响,所以str2的地址没有改变,因此指向的还是second。

所以说,要改变传递之后的结果,要用ref和out来修饰。

说了这么多,事实上我觉得自己理解的还不是那么透彻,以后再结合具体实例多加磨练吧,积累多了可能理解的就更好了。