c#引用传递和值传递
我们知道,c#的数据类型分为值类型和引用类型。值类型包括基本类型(数值类型,bool类型等)、结构和枚举,引用类型包括类、委托、数组等。在使用方法传递变量时,就需要了解值类型和引用类型作为参数传递的机制了。
先看下面一段代码:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int aNumber = 10;
A a = new A();
a.Name = "aaaaaaaa";
Console.WriteLine(aNumber);
Console.WriteLine(a.Name);
ToDouble(aNumber);
ToDouble(a);
Console.WriteLine(aNumber);
Console.WriteLine(a.Name);
Console.ReadKey();
}
static void ToDouble(int number)
{
number *= 2;
}
static void ToDouble(A a)
{
a.Name += "ssssssss";
}
}
class A
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
}
输出结果为:
10
10
10
1010
通过结果发现,值类型aNumber在经过函数处理后,再次输出时值并没有发生变化,而引用类型class A的属性发生了变化,为什么会发生这种情况?
数据类型在内存中的保存时,值类型保存在堆栈中,引用类型将它的值保存在托管堆中,在堆栈中保存的是对堆上地址的引用,在方法中传递参数时,所有类型都是传递堆栈中的位置,具体过程为先在堆栈上复制一个传递的对象,然后将该对象传给参数,所以显而易见,数值类型保存在堆栈中,作为参数传递时直接复制了数值的一个副本给方法,方法对该副本所做的任何操作都不会影响到该数值的原值,但是引用类型复制的是堆栈上对堆的引用,该引用指向的仍然是堆上的引用类型,所以对应用类型所做的操作都会引起其本身的改变。
下面我们再看一段代码:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string aStr="10";
Console.WriteLine(aStr);
ToDouble(aStr);
Console.WriteLine(aStr);
Console.ReadKey();
}
static void ToDouble(string aStr)
{
aStr+=aStr;
}
}
}
输出结果为:
10
10
string类型是引用类型,所以在方法中传递的仍然是堆栈中对string变量引用的副本,但是为什么上面的代码并没有改变string变量的值呢?这里我们就需要知道,在c#中,string是一个比较特殊的类型,微软并不提倡我们些如下的代码:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string aStr="aaaaa";
string aOtherStr="bbbbb";
string theyConcat=aStr+aotherStr;
}
}
}
上面的代码首先声明了一个变量aStr,然后将其与另一个字符串连接,在具体实现过程中,系统先在托管对中保存了aaaaa值,在进行连接运算时,先将aaaaa的值复制一份,然后在后面连接bbbbb,最后将得到的新值的地址赋给aStr,所以此时aaaaa并没有在内存中删除,直到垃圾回收器将其回收。比较好的做法是在需要进行连接字符串操作时,使用StringBulider类进行操作,它会直接在对象后面进行连接操作,而不会先将值复制一遍。
回到上面的方法来,当String类型作为参数传递时,系统会先在托管堆中将值复制一遍,堆栈上得到的地址指向这个新值,所以方法对string类型的操作并不影响到它的原有值。
这里我们必然会想到,如果我需要使用一个方法改变值类型的值咋办呢?比如说,当我们需要一个方法输出多个值时,我们知道,当方法有返回值时,最后return回来的总是只有一个值,如果我需要将参数a、b同时传入方法并得到两个结果时,怎么办呢?此时就需要使用引用传递了。c#的方法使用了ref关键字,该关键字表示将参数作为引用类型传递,看下面的代码:
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 50;
Console.WriteLine(a);
Console.WriteLine(b);
ToDouble(ref a,ref b);
Console.WriteLine(a);
Console.WriteLine(b);
Console.ReadKey();
}
&
补充:软件开发 , C# ,