本章内容:
方法的结构
方法体内部的代码执行
局部变量
局部常量
控制流
方法调用
返回值
返回语句和void方法
局部函数
参数
值参数
引用参数
引用类型作为值参数和引用参数
输出参数
参数数组
参数类型总结
方法重载
命名参数
可选参数
栈帧
递归
参数数组
至此,在本书所述的参数类型中,一个形参必须严格地对应一个实参。参数数组则不同,它
允许特定类型的零个或多个实参对应一个特定的形参。参数数组的重点如下。
在一个参数列表中只能有一个参数数组。
如果有,它必须是列表中的最后一个。
由参数数组表示的所有参数必须是同一类型。
声明一个参数数组时必须做的事如下。
在数据类型前使用params修饰符。
在数据类型后放置一组空的方括号。
下面的方法头展示了int型参数数组的声明语法。在这个示例中,形参inVals可以代表零
个或多个int实参。

类型名后面的空方括号指明了参数是一个整数数组。在这里不必在意数组的细节,它们将在
第13章详细阐述。而现在,你需要了解的内容如下。
数组是一组有序的同一类型的数据项。
数组使用一个数字索引进行访问。
数组是一个引用类型,因此它的所有数据项都保存在堆中。
方法调用
可以使用两种方式为参数数组提供实参。
- 一个用逗号分隔的该数据类型元素的列表。所有元素必须是方法声明中指定的类型。
csharp
ListInts(10,20,30) //3个int
- 一个该数据类型元素的一维数组。
csharp
int[] intArray={1,2,3};
ListInts(intArray); //一个数组变量
请注意,在这些示例中,没有在调用时使用params修饰符。参数数组中修饰符的使用与其
他参数类型的模式并不相符。
- 其他参数类型是一致的,要么都使用修饰符,要么都不使用修饰符。
- 值参数的声明和调用都不带修饰符。
- 引用参数和输出参数在两个地方都需要修饰符。
- params修饰符的用法总结如下。
- 在声明中需要修饰符。
- 在调用中不允许有修饰符。
延伸式
方法调用的第一种形式有时被称为延伸式 ,这种形式在调用中使用独立的实参。
例如,下面代码中的方法ListInts的声明可以匹配其后所有的方法调用,虽然它们的实参
数目不同。
csharp
void ListInts(params int[] inVals) //方法声明
{
....
}
...
ListInts(); //0个实参
ListInts(1,2,3); //3个实参
ListInts(4,5,6,7); //4个实参
ListInts(8,9,10,11,12) //5个实参
在使用一个为参数数组使用独立实参的调用时,编译器做下面几件事。
- 接受实参列表,用它们在堆中创建并初始化一个数组。
- 把数组的引用保存到栈中的形参里。
- 如果在对应形参数组的位置没有实参,编译器会创建一个有零个元素的数组来使用。
例如,下面的代码声明了一个名为ListInts的方法,它接受有一个参数数组。Main声明了
3个整数并把它们传给了数组。
csharp
class MyClass
{
public void ListInts(params int[] inVals) //参数数组
{
if((inVals!=null)&&(inVals.Length!=0))
{
for(int i=0;i<inVals.Length;i++)//处理数组
{
inVals[i]=inVals[i]*10;
Console.WriteLine($"{inVals[i]}");//显示新值
}
}
}
}
class Program
{
static void Main()
{
int first=5,second=6,third=8; //声明3个int
MyClass mc=new MyClass();
mc.ListInts(first,second,third);//调用方法 实参
Console.WriteLine($"{first},{second},{thrid}");
}
}
图6-12阐明了在方法执行的不同阶段实参和形参的值。
-
方法调用之前,3个实参已经在栈里。
-
在方法的开始,3个实参被用于初始化堆中的数组,并且数组的引用被赋值给形参
inVals。
-
在方法内部,代码首先检查以确认数组引用不是null,然后处理数组,把每个元素乘以
10并保存回去
-
方法执行之后,形参inVals失效。
关于参数数组,需要记住的一点是当数组在堆中被创建时,实参的值被复制到数组中。这样,
它们像值参数。
-
如果数组参数是值类型,那么值被复制,实参在方法内部不受影响。
-
如果数组参数是引用类型,那么引用被复制,实参引用的对象在方法内部会受到影响。

将数组作为实参
也可以在方法调用之前创建并组装一个数组,把单一的数组变量作为实参传递。这种情况下,
编译器使用你的数组而不是重新创建一个。
例如,下面的代码使用前一个示例中声明的方法ListIntso在这段代码中,Main创建一个
数组,并用数组变量而不是使用独立的整数作为实参。
static void Main()
{
int[] myArr=new int[]{5,6,7};//创建并初始化数组
MyClass mc=new MyClass();
mc.ListInts(myArr); //调用方法来打印值
foreach(int x in myArr)
Console.WriteLien($"{x}");//输出每个元素
}
参数类型总结
因为有4种参数类型,所以有时很难记住它们的不同特征。表6-2对它们做了总结,以便于
比较和对照。
