无论学习C,C++还是C#,都有人在引用上迷糊。在这里我就给大家说明一下引用。为了便于观看,我会通过例子和示意图来说明。
先来了解一下,什么是值类型,什么是引用类型。
值类型:
int i = 50;
int i_copy = i;
i和i_copy分别是两个不同的变量,占用了两个不同的空间,改变一个不会造成另一个的改变。
示例代码:
static void ttt(int i1)
{
Console.WriteLine("函数内i1重新赋值前 i1 = " + i1);
i1 = 2;
Console.WriteLine("函数内i1重新赋值后 i1 = " + i1);
}
static void Main(string[] args)
{
int i = 50;
Console.WriteLine("函数调用前 i = " + i);
ttt(i);
Console.WriteLine("函数调用后 i = " + i);
}
自定义了一个类A
代码如下
class A
{
public int a;
public A(int par)
{
a = par;
}
}
引用类型:
A a1= new A(50);
A a2 = a1;
a1是一个引用,存放的不是具体的值,而是一个地址变量,指向new出来的一个对象的地址,这个对象在堆中存放。a2也是一个引用,把a2 = a1,是把a1中存放的地址变量赋值给a2,这样a2也指向了在堆中new出来的那个对象。如果改变任何一个的数值,改变的是堆中的数据,另一个的值也会改变。
示例代码:
static void sss(A a2)
{
Console.WriteLine("函数内a2.a重新赋值前 a2.a = " + a2.a);
a2.a = 2;
Console.WriteLine("函数内a2.a重新赋值后 a2.a = " + a2.a);
}
static void Main(string[] args)
{
A a1 = new A(42);
Console.WriteLine("函数调用前 a1.a = " + a1.a);
sss(a1);
Console.WriteLine("函数调用后 a1.a = " + a1.a);
}
通过上面可以看出,int定义的是一个值类型,而自定义的类在定义变量时,是引用。
如果我们想将int类型的变量像自定义类一样,在函数中通过引用传递。该如何呢?
我们可以用在参数传递时加ref
示例代码
static void ttt1( ref int i1)
{
Console.WriteLine("函数内i1重新赋值前 i1 = " + i1);
i1 = 2;
Console.WriteLine("函数内i1重新赋值后 i1 = " + i1);
}
static void Main(string[] args)
{
int i = 50;
Console.WriteLine("函数调用前 i = " + i);
ttt1(ref i);
Console.WriteLine("函数调用后 i = " + i);
}
调用时和定义时都要加ref
此时,被调函数的值改变,主函数的值也被改变。
无论是通过引用传递还是值传递,都要将实参进行初始化才行使用,如果不初始化,编译阶段会报错。
我们可以用用out替代ref
static void ttt2(out int i1)
{
i1 = 2;
Console.WriteLine("函数内i1赋值后 i1 = " + i1);
}
static void Main(string[] args)
{
int i ;
ttt2(out i);
Console.WriteLine("函数调用后 i = " + i);
}
这种情况下,调用前可以不对实参初始化,无论对不对实参初始化,再函数内,必须形参初始化才能使用,不然会报错。形参在函数体内的改变,会影响函数体外的实参的改变。这种情况下传递的是引用。