可能很多人不理解为啥子这个要单独开一章,不过我得说一下,这个真的很重要,得搞清楚了,不能混淆了。
参数分三种:值参数,引用参数和输出参数
在这之前先说一下形参和实参的概念。
形参:本地变量,声明在方法的参数列表中,而不是在方法体内。很正规的说法,其实很简单,举个栗子就懂了。
eg:
public void SetParameter(int a1,float b1)
{
...
}
其中a1,b1就是形参。
实参:用于初始化形参的表达式或变量。也说得很规范,同样的给个例子。
eg:
static void Main()
{
float b1 = 0;
SetParameter(10,b1);
}
其中10和b1就是实参了。
说到这里形参和实参的概念是不是就懂了,下面开始说一下值参数和引用参数吧。
值参数:通过将实参的值复制给形参的方式把数据传递到方法中。
要点:1.在栈中为形参分配空间
2.将实参的值复制给形参
引用参数:
要点:1.使用引用参数时,必须在方法的声明和调用中都是用ref修饰符。
2.实参必须是变量,在用做实参前必须被赋值。
输出参数:用于从方法体内把数据传出到调用代码,与引用参数类似。
要点:1.使用输出参数时,必须在方法的声明和调用中都是用out修饰符。
2.实参必须是变量,在方法体内被初始化,这一点与ref是不一样的地方。
这里需要说明一下ref的作用。我的理解就是一个引用指向堆里的数据,这个引用的改变会影响数据的改变。
eg:
static int a11 = 1;
static float b11 = 2;
static void SetParameter(int a1, ref float b1)
{
a1 = 10;
b1 = 20;
Console.WriteLine("a1Copy:" + a1);
Console.WriteLine("b1Copy:" + b1);
}
static void Main()
{
Console.WriteLine("Before:a11:{0},b11:{1}", a11, b11);
SetParameter(a11, ref b11);
Console.WriteLine("Late:a11:{0},b11:{1}", a11, b11);
Console.ReadKey();
}
输出结果就是:
这里可以发现如果SetParameter函数的方法体中引用形参b1改变为20的情况下,堆里的数据也会发生改变,也就是b11变成了20。这就是ref的作用了,会对堆里的数据造成影响。
而这里又会引申出另一个问题,就是如果引用类型作为值参数和引用参数的时候会有什么不同呢。
1.将引用类型作为值参数传递 如果在方法内创建一个新对象并赋值给形参,将切断形参与实参之间的关联,并且在方法调用结束后,新对象将不复存在(被释放掉)。
2.将引用类型对象作为引用参数传递 如果在方法内创建一个新对象并赋值给形参,在方法结束后该对象依然存在,并且是实参所引用的值。
有点文绉绉的,那么我们继续使用栗子。
第一种情况是这样子的:
class MyClass
{
public int myClassData = 10;
}
class Program
{
static void SetParameter(MyClass mc)
{
mc.myClassData = 20;
Console.WriteLine("Set Data:" + mc.myClassData);
mc = new MyClass();
Console.WriteLine("After new then Set Data:" + mc.myClassData);
}
static void Main()
{
MyClass mc2 = new MyClass();
Console.WriteLine("Before:" + mc2.myClassData);
SetParameter(mc2);
Console.WriteLine("Late:" + mc2.myClassData);
Console.ReadKey();
}
}
大家猜一下结果如何呢?
enmmmm,直接上结果了。
有没有意外?为什么mc2.myClassData的值会改变呢?别忘了哦,传递的是一个引用参数哦,mc2和mc是两个不同的引用指向同一个堆里的数据,而在SetParameter函数中mc重新new了一下,是不会改变mc2的值的。这就是第一种情况。
而第二种情况是这样子的:
class MyClass
{
public int myClassData = 10;
}
class Program
{
static void SetParameter(ref MyClass mc)
{
mc.myClassData = 20;
Console.WriteLine("Set Data:" + mc.myClassData);
mc = new MyClass();
Console.WriteLine("After new then Set Data:" + mc.myClassData);
}
static void Main()
{
MyClass mc2 = new MyClass();
Console.WriteLine("Before:" + mc2.myClassData);
SetParameter(ref mc2);
Console.WriteLine("Late:" + mc2.myClassData);
Console.ReadKey();
}
}
就增加了一个ref的关键字,那么结果如何呢?直接上结果了。
Late的结果俨然不同,这其中的原因就是ref的作用了。
好了,说了那么多就讲到这里了,有不懂的下面回复吧。