类 函数成员 给方法传递参数
参数可以通过引用或通过值传递给方法。在变量通过引用传递给方法时,被调用的方法得到的就是这个变量,所以在方法内部对变量进行的任何改变在方法退出后仍旧有效;而如果通过值传送给方法,被调用的方法得到的是变量的一个相同副本,也就是说,在方法退出后,对变量进行的修改会丢失。对于复杂的数据类型,按引用传递的效率更高,因为在按值传递时,必须复制大量的数据。
在C#中,除非特别说明,所有的参数都通过值来传递。但是,在理解引用类型的含义时需要注意。因为引用类型的变量只包含对象的引用,将要复制的正是这个引用,而不是对象本身,所以对底层对象的修改会保留下来。相反,值类型的对象包含的是实际数据,所以传递给方法的是数据本身的副本。例如,int通过值传递给方法,对应方法对int的值所做的任何改变都没有改变原int对象的值。但如果把数组或其他引用类型(如类)传递给方法,对于的方法就会使用改引用改变这个数组中的值,而新值会反射在原始数组对象上。
观看下面的ParameterTest.cs来感受一下这两种数据类型传递的区别:
using System; namespace Wrox { class ParameterTest { static void SomeFunction(int[] ints, int i) { ints[0] = 100; i = 100; } public static void Main() { int i = 0; int[] ints = { 0, 1, 2, 4, 8 }; Console.WriteLine("i=" + i); Console.WriteLine("int[0]=" + ints[0]); SomeFunction(ints, i); Console.WriteLine("i=" + i); Console.WriteLine("int[0]=" + ints[0]); return; } } }
输出结果为:
i=0
int[0]=0
i=0
int[0]=100
注意,i的值保持不变,而在ints中改变的值在原始数组中改变了。
注意字符串的行为方式有所不同,因为字符串是不可变的(如果改变字符串的值,就会创建一个全新的字符串)所以字符串无法采用一般引用类型的行为方式。在方法调用中,对字符串所做的任何改变都不会影响原始字符串。
ref参数
如前所述,通过值传送变量是默认的,也可以迫使值参数通过引用传递给方法。为此,要使用ref关键字。如果把一个参数传递给方法,且这个方法的输入参数前带有 ref关键字,则 该方法对变
量所做的任何改变都会影响原始对象的值 :
static void SomeFunction(int[] ints, ref int i) { ints[0] = 100; i = 100; }
在调用该方法时,还需要添加ref关键字 :
SomeFunction(ints, ref i);
此时,输出结果为:
i=0
int[0]=0
i=100
int[0]=100
最后,C#仍要求对传递给方法的参数进行初始化,理解这一点也非常重要。在传递给方法之前,无论是按值传递,还是按引用传递;如何变量都必须初始化。
out参数
C#要求变量在被引用前必须用一个初始值进行初始化。尽管在把输入变量传递给函数前,可以用没有意义的值初始化它们,因为函数将使用真实、有意义的值初始化它们,但是这样做是没有必要的,又是甚至会引起混乱。但有一种方法能够简化C#编译器所坚持的输入参数的初始化。
编译器使用out关键字来初始化。在方法的输入参数前面加入out前缀时,传递给该方法的变量可以不初始化。该变量通过引用传递,所以在从被调用的方法中返回时,对应方法对该变量进行的任何改变都会保留下来。在调用该方法时,还需要使用out关键字,与在定义该方法时一样:
命名参数
参数一般需要按定义的顺序传递给方法。命名参数允许按任意顺序传递。所以下面的方法:
string FullName(string firstName, string lastName)
{
return firstName + "" + lastName;
}
下面的方法调用会返回相同的全名:
FullName("John", "Miss Zhou")
FullName(lastName: "Miss Zhou", firstName: "John");
如果方法有几个参数,就可以在同一个调用中混合使用位置参数和命名参数。
可选参数
参数也可以是可选的。必须为可选参数提供默认值。可选参数还必须是方法定义的最后一个参数。所以下面的方法声明是不正确的:
void TestMethod(int optionalNumber = 10, int notOptionalNumbear) { }
要是这个方法正常工作,就必须在最后定义optionalNumber参数。