二、方法的参数
1.值参数
在方法声明时不加修饰符的形参就是值参数,它表明实参与形参之间按值传递。当这个方法被调用时,编译器为值参数分配存储单元,然后将对应实参的值复制到形参中。实参可以是变量、常量、表达式,但要求其值的类型必须与形参声明的类型一致或能被隐式地转化为相同类型。
演示当Sort方法传递值参数时,对形参的修改不影响其实参:
using System;
namespace ConsoleApp3
{
class Myclass
{
public void Sort( int x, int y, int z)
{
int tmp; //tmp是方法Sort的局部变量
//将x,y,z按小到大排序
if (x > y) { tmp = x; x = y; y = tmp; }
if (x > z) { tmp = x; x = z; z = tmp; }
if (y > z) { tmp = y; y = z; z = tmp; }
}
}
class Test
{
static void Main(string []args)
{
Myclass m = new Myclass();
int a, b, c;
a = 30;b = 20;c = 10;
m.Sort( a, b, c);
Console.WriteLine("a={0},b={1},c={2}",a, b, c);
Console.Read();
}
}
}
演示当方法传递一个引用对象(如数组)时,对形参的修改会影响到实参:
using System;
namespace ConsoleApp3
{
class Myclass
{
public void SortArray(int[] a)
{
int j, pos, tmp;
for (int i = 0; i < a.Length - 1; i++)
{
for(pos=j=i;j<a.Length;j++)
{
if (a[pos] > a[j]) pos = j;
if(pos!=i)
{
tmp = a[i];
a[i] = a[pos];
a[pos] = tmp;
}
}
}
}
}
class Test
{
static void Main(string[] args)
{
Myclass m = new Myclass();
int[] score = { 87, 89, 56, 90, 100, 75, 64, 45, 80, 84 };
m.SortArray(score);
for (int i = 0; i < score.Length; i++)
{
Console.WriteLine("score[{0}]={1}", i,score[i]);
//if (i == 4) Console.WriteLine();
}
Console.Read();
}
}
}
2.引用参数
如果调用一个方法,期望能够对传递给它的实际变量进行操作,就要使用 C#的 ref 修饰符来解决此类问题,ref修饰符将告诉编译器,实参与形参的传递方式是引用。
与值参数不同,引用参数并不创建新的存储单元,它与方法调用中的实在参数变量同处在一个存储单元。因此,在方法内对形参的修改就是对外部实参变量的修改。
将程序中Sort方法的值参数传递方式改成引用传递方式:
using System;
namespace ConsoleApp3
{
class Myclass
{
public void Sort(ref int x, ref int y, ref int z) //ref
{
int tmp; //tmp是方法Sort的局部变量
//将x,y,z按小到大排序
if (x > y) { tmp = x; x = y; y = tmp; }
if (x > z) { tmp = x; x = z; z = tmp; }
if (y > z) { tmp = y; y = z; z = tmp; }
}
}
class Test
{
static void Main(string[] args)
{
Myclass m = new Myclass();
int a, b, c;
a = 30; b = 20; c = 10;
m.Sort(ref a, ref b, ref c); //ref
Console.WriteLine("a={0},b={1},c={2}", a, b, c);
Console.Read();
}
}
}
}
3.输出参数
函数的返回值一般来说只有一个,但是,有时候我们需要返回的值超过了一个,C#为此有了一种新型的参数类型———输出参数,输出参数的格式如下:
函数类型 函数名(out 参数类型 参数名称)
输出参数和引用参数类似,它也不产生新的存储空间。
两者的区别在于:out参数只能从方法中传出值,而不能从方法调用处接受参数值;在方法体内out参数被认为是从未赋过值的,所以在方法结束之前,应该对out参数赋值。
求一个数组中所有元素的最大、最小和平均值。
本例希望得到三个返回值,显然用方法的返回值不能解决,且这三个值必须通过计算得到,初始值没有意义,所以解决方案是定义三个out参数。
using System;
namespace ConsoleApp3
{
class Myclass
{
public void MaxMinArray(int[] a, out int max, out int min, out double avg)
{
int sum;
sum = max = min = a[0];
for (int i = 1; i < a.Length; i++)
{
if (a[i] > max) max = a[i];
if (a[i] < min) min = a[i];
sum += a[i];
}
avg = sum / a.Length;
}
}
class Test
{
static void Main(string[]args)
{
Myclass m = new Myclass();
int[] score = { 87, 89, 56, 90, 100, 75, 64, 45, 80, 84 };
int smax, smin;
double savg;
m.MaxMinArray(score, out smax, out smin, out savg);
Console.WriteLine("Max={0},Min={1},Avg={2}",smax,smin,savg);
Console.ReadLine();
}
}
}
定义两个方法 Swap1 和 Swap2,它们都有两个引用对象作为参数,但 Swap2 的参数加了 ref 修饰,演示调用这两个方法产生的结果。
using System;
namespace ConsoleApp3
{
class Myclass
{
public void Swap1(string s,string t)
{
string tmp;
tmp = s;
s = t;
t = tmp;
}
public void Swap2(ref string s,ref string t)
{
string tmp;
tmp = s;
s = t;
t = tmp;
}
}
class Test
{
static void Main(string[]args)
{
Myclass m = new Myclass();
string s1 = "ABCDEFG", s2 = "1234567";
m.Swap1(s1, s2); //s1,s2的引用并没有改变
Console.WriteLine("s1={0}", s1);
Console.WriteLine("s1={0}", s2);
Console.WriteLine();
m.Swap2(ref s1,ref s2); //s1,s2的引用交换了
Console.WriteLine("s1={0}", s1);
Console.WriteLine("s1={0}", s2);
Console.Read();
}
}
}
4.参数数组
比如,在3个数中找最大、最小和在 5 个数中找最大、最小数,甚至在任意多个数中找最大、最小数的程序中能使用同一个方法。C#提供了传递可变长度参数表的机制来解决此问题,可以使用 params 关键字来指定一个可变长的参数表。
params关键字指明一个输入参数,此参数输入将被视为一个参数数组,这种类型的输入参数只能作为方法的最后一个参数。
演示Myclass类中的方法MaxMin有一个参数数组类型的参数,在调用这个方法时具有灵活性:
using System;
namespace ConsoleApp3
{
class Myclass
{
public void MaxMin(out int max,out int min,params int[]a)
{
if(a.Length==0)//如果可变参数为零个,可以取一个约定值或产生异常
{
max = min = -1;
return ;
}
max = min = a[0];
for (int i = 1; i<a.Length; i++)
{
if (a[i] > max) max = a[i];
if (a[i] < min) min = a[i];
}
}
}
class Test
{
static void Main(string []args)
{
Myclass m = new Myclass();
int[] score = { 87, 89, 56, 90, 100, 75, 64, 80, 84 };
int smax, smin;
m.MaxMin(out smax, out smin); //可变参数个数可以是零个
Console.WriteLine("Max={0},Min={1}", smax, smin);
m.MaxMin(out smax, out smin, 45, 76, 89, 90); //在4个数之间找最大、最小
Console.WriteLine("Max={0},Min={1}", smax, smin);
m.MaxMin(out smax, out smin, score);
Console.WriteLine("Max={0},Min={1}", smax, smin);
Console.Read();
}
}
}