使用这些关键字来控制参数如何传人目标方法:
参数修饰符 | 作用 |
---|---|
无 | 按值传递,意味着被调用的方法收到原始数据的一份副本 |
out | 输入参数由被调用的方法赋值,因此按引用传递,如果被调用的方法没有给输出参数赋值,就会出现编译错误 |
ref | 调用者赋值,并且可以由被调用的方法重新赋值(因为数据是按引用传递的)。如果被调用的方法未给ref参数赋值,也不会有编译错误 |
params | 这个参数修饰符允许将一组可变数量的参数作为单独的逻辑参数进行传递。方法只能有一个params修饰符,而且必须是方法的最后一个参数。事实上,你不会经常使用params修饰符。但要知道的是,基础类库中的许多方法都使用了这个C#语言特性 |
1.默认的参数传递行为
static void DefaultArg()
{
Console.WriteLine("*****Fun with Methods*****");
int x = 9, y = 10;
Console.WriteLine("Before call:X:{0},Y:{1}", x, y);
Console.WriteLine("Answer is:{0}", Add(x, y));
Console.WriteLine("After call:X:{0},Y:{1}", x, y);
//不需要给作为输出参数的本地变量赋初值,假设第一次使用它们时是将其作为输出参数的
int ans;
Add(90, 90, out ans);
Console.WriteLine("90+90={0}", ans);
}
static int Add(int x, int y)
{
int ans = x + y;
//由于我们修改的是原始数据的副本,调用者不会看到这些改变
x = 10000;
y = 88888;
return ans;
}
static void Add(int x, int y, out int ans)
{
ans = x + y;
}
/*output:
*****Fun with Methods*****
Before call:X:9,Y:10
Answer is:19
After call:X:9,Y:10
90+90=180
*/
2.out参数修饰符
前面的例子说明,实际上没有必要用输出参数返回这两个数的和。然而C#的out修饰符有一个很有用的用途:通过它,调用者只使用一次方法调用就可以获得多个返回值。
static void FillTheseValue(out int a, out string b, out bool c)
{
a = 9;
b = "Enjoy your string";
c = true;
}
static void OutArg()
{
int i; string str; bool b;
FillTheseValue(out i, out str, out b);
Console.WriteLine("{0},{1},{2}", i, str, b);
}
/*output:
9,Enjoy your string,True
*/
3.ref参数修饰符(这个关键字的行为会根据参数是值类型(结构)还是引用类型(类)而变化)
如果希望方法可以对在调用者作用域中声明的不同数据进行操作(通常是改变他的值),例如,排序何交换例程,就必须使用引用参数。
输出参数和引用参数的区别是
- 输出参数不需要在他们被传递给方法之前初始化,因为方法在退出之前必须为输出参数赋值。
- 引用参数必须在他们被传递给方法之前初始化,因为是在传递一个对已存在变量的引用。如果不付给他初始值,就相当于要对一个未赋值的本地变量进行操作。
static void SwapStrings(ref string s1, ref string s2)
{
string tempStr = s1;
s1 = s2;
s2 = tempStr;
}
static void RefArg()
{
string str1 = "Flip";
string str2 = "Flop";
Console.WriteLine("Before:{0},{1}", str1, str2);
SwapStrings(ref str1, ref str2);
Console.WriteLine("After:{0},{1}", str1, str2);
}
/*output:
Before:Flip,Flop
After:Flop,Flip
*/
4,params参数修饰符
C#使用params关键字支持参数数组的使用。params关键字可以把可变数量的参数(相同类型)作为单个逻辑参数传给方法。
static double CalculateAverage(params double[] values)
{
Console.WriteLine("You sent me {0} doubles.", values.Length);
double sum = 0;
if (values.Length == 0)
return sum;
for (int i = 0; i < values.Length; i++)
sum += values[i];
return (sum / values.Length);
}
static void ParamsArg()
{
double average;
average = CalculateAverage(4.0, 3.2, 5.7, 64.22, 87.2);
Console.WriteLine("Average of data is :{0}", average);
double[] data = { 4.0, 3.2, 5.7 };
average = CalculateAverage(data);
Console.WriteLine("Average of data is :{0}", average);
Console.WriteLine("Average of data is :{0}", CalculateAverage());
}
/*output:
You sent me 5 doubles.
Average of data is :32.864
You sent me 3 doubles.
Average of data is :4.3
You sent me 0 doubles.
Average of data is :0
*/
5,可选参数
通过给参数指定默认值从而允许方法的调用者可以不指定不必要的参数
static void EnterLogData(string message,string owner="Programmer")
{
//dosothing
}
static void Main(string[] args)
{
//第一个owner为默认值Programmer,第二个owner值为指定值owner
EnterLogData("message");
EnterLogData("message","owner");
}
//**分配给可选参数的值必须在编译时确定,而不能在运行时确定**
static void EnterLogData(string message,string owner="Programmer",DateTime time=DateTime.Now)
{
//dosomethings
}
//这将无法通过编译,因为DateTime类的Now属性是在运行时而不是在编译时处理的
notice:为了避免歧义,可选参数必须放在方法签名的最后!