C# 参数传递
我们都知道在C#中参数传递方式有两种:值传递和引用传递。下面分别说说这两种传递方式。
一、引用传递。
引用传递又分为ref参数和out参数。
他们的区别在于:对于ref参数来说,必须在调用方法之前初始化这个参数,并且这个值将在方法内部被引用。
out 参数则没有必要再调用方法之前初始化,而必须在方法内部初始化。因此你在调用方法之前的值将不起作用。
我们看下面的代码:
class Program { static void Main(string[] args) { int resultAdd = 3; Add(1, 2, ref resultAdd); Console.WriteLine("x + y = {0}", resultAdd); int resultSub = 3; Sub(1, 2, out resultSub); Console.WriteLine("x - y = {0}", resultSub); Console.ReadLine(); } public static void Add(int x, int y, ref int result) { result = result + x + y; } public static void Sub(int x, int y, out int result) { result = 0; result = x - y - result; }
运行我们可以得到如下结果:
如果我们把resultAdd初始化去掉,则编译会产生Error 1 Use of unassigned local variable 'resultAdd' 。
同样如果把Sub方法里面的result初始化注释掉,也会产生这个错误。
二、值传递
在值传递的时候,被调用的方法会得到一个变量的拷贝。这里有一个我们容易产生错误的地方。就是应用数据类型的值传递。我们往往会把应用类型的值传递也叫着引用传递。这是不正确的。对于应用类型的值传递来说,被调用的方法得到了该引用的拷贝,也就是说产生一个和变量指向同一地址的引用。
我们对于引用类型(如类,数组)的值传递,如果在被调用的方法里面改变对象里面某个成员或变量的值,那么在调用方法时传递的对象的对应的值也会被改变。但是如果在被调用的方法里面改变该对象引用的值,在调用方法时传递的对象的值是不会被改变的。看下面的代码:
我们定义个简单的类:
public class People { public People()
{
Name = "";
}
public People(string name, int age) { Name = name; Age = age; } public string Name { get; set; } public int Age { get; set; } }
简单的测试方法:
static void Main(string[] args) { People p1 = new People("细小猛", 23); People p2 = new People("xixiaomeng", 32); ModifyPeople(p1, p2); Console.WriteLine("p1:Name:{0} Age:{1}", p1.Name, p1.Age); Console.WriteLine("p2:Name:{0} Age:{1}", p2.Name, p2.Age); Console.ReadLine(); } public static void ModifyPeople(People p1, People p2) { People p = new People(); p.Name = p1.Name; p.Age = 24; p1 = p; p2.Age = 24; }
运行可以得到下面的结果:
可以看到p1的Age值并没有被改变。如果希望这种情况下p1的值也被改变的话,在参数上加上ref关键字就可以了。
Note:在所有类型的基类中,有一个保护方法MemberWiseClone(),这的方法实现浅度克隆。这个方法对对象的里面的引用的成员的克隆方式和引用类型的值传递方式是一样。也就说对对象里面的引用成员只是拷贝了引用,但仍然和原来对象的里面的引用成员指向同一个地址。