引用参数(ref)

当参数类型为引用参数时,实参必须是变量,在用作实参前必须被赋值!如果是引用类型变量,可以赋值为一个引用或null。
函数声明和调用时都需要在ref参数前加上”ref”

1
2
3
4
void RefTest(ref int a){ ... }
int a = 3;
RefTest(ref a);
RefTest(3);//报错,必须为变量

对于值参数,系统会在栈上为形参分配内存,而引用参数不会在栈上分配内存,形参的参数名将作为实参变量的别名指向相同的内存位置。
将引用类型对象作为值参数传递时:如果在方法内创建一个新对象并赋值给形参,在方法调用结束后,将切断形参和实参的关联,新对象也不复存在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
class Program {
static void Main(string[] args) {
//调用前
Student std = new Student();
std.age = 20;
Console.WriteLine("执行前"+std.age);
MakeStd(std);
Console.WriteLine("执行后"+std.age);
}
static void MakeStd(Student std) {
std.age = 50;
Student std2 = new Student();
std2.age = 20;
std = std2;
Console.WriteLine("执行中:"+std.age);
}
}
public class Student {
public int age { get; set; }
}

值参数
将引用类型的对象作为引用参数传递时:如果在方法内创建一个新对象并赋值给形参,在方法调用结束后,该对象依然存在,并且是实参所引用的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
class Program {
static void Main(string[] args) {
//调用前
Student std = new Student();
std.age = 20;
Console.WriteLine("执行前"+std.age);
MakeStd(ref std);
Console.WriteLine("执行后"+std.age);
}
static void MakeStd(ref Student std) {
std.age = 50;
Student std2 = new Student();
std2.age = 20;
std = std2;
Console.WriteLine("执行中:"+std.age);
}
}
public class Student {
public int age { get; set; }
}

应用参数

输出参数(out)

函数声明和调用时都需要在out参数前加上”out”。
实参必须是变量。
在方法内部,给输出参数赋值之后才能读取它。
方法返回之前,每条可能的路径都必须为输出参数赋值。
不可能使用输出参数把数据传入方法。
形参的名称被设置为实参的别名,可以认为形参实参指向相同内存位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
class Program {
static void Main(string[] args) {
MyClass a1 = null;
int a2;
MyMethod(out a1, out a2);
Console.WriteLine(a1.val);
Console.WriteLine(a2);
}
static void MyMethod(out MyClass f1 , out int f2) {
f1 = new MyClass();
f1.val = 25;
f2 = 15;
}
}
public class MyClass {
public int val = 20;
}
1
2
3
4
5
6
static void Main(){
MyMethod(out MyClass a1 , out int a2);
Cosole.WriteLine(a2);
Cosole.WriteLine(a1.val);
a2++;
}

out

参数数组(params)

一个参数列表中只能有一个参数数组,并且它必须是列表最后一个。
参数数组表示的所有参数必须是同一类型。

1
2
3
4
5
6
7
8
9
10
11
12
class Program {
static void Main(string[] args) {
ParamsTest(9, 8, 7, 6, 5, 4, 3, 2, 1);
int[] ints = {7,6,5,4,3,2,1};
ParamsTest(9,8,ints);
}
static void ParamsTest(int a, int b ,params int[] vals) {
foreach(int i in vals) {
Console.WriteLine(i);
}
}
}

ref局部变量与ref返回

ref局部变量:
相当于一个变量的别名,即使引用的对象是值类型。
对任意一个变量的赋值都会反映到另一个变量上。
ref变量声明时必须初始化。

1
2
int x;
reg int y = ref x;

ref返回:
ref返回提供了一种使方法返回变量引用而不是变量值的方法。
函数声明返回值类型前有ref。
函数内部return后有ref。
函数调用时函数名前有ref。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Program {
static void Main(string[] args) {
int a = 3, b = 4;
ref int max = ref Max(ref a, ref b);
Console.WriteLine(++max);
Console.WriteLine(a);
Console.WriteLine(b);
}
static ref int Max(ref int a, ref int b) {
if (a > b) return ref a;
else return ref b;
}
}

命名参数

只要显式指定参数的名字,就可以以任意顺序在方法中列出实参。

1
2
3
4
5
6
7
8
9
10
class Program {
static void Main(string[] args) {
int val;
val = Calc(c: 4, a: 1, b: 8);
Console.WriteLine(val);
}
static int Calc(int a, int b,int c) {
return (a+b) * c;
}
}

可选参数(参数默认值)

不是所有参数类型都可以作为可选参数:
只要值类型的默认值在编译的时候可以确定,就可以使用值类型作为可选参数。
只有在默认值为null的时候,引用类型才可以用作可选参数。

1
2
3
4
5
6
7
8
9
10
class Program {
static void Main(string[] args) {
int val;
val = Calc(1,2);
Console.WriteLine(val);
}
static int Calc(int a, int b , int c = 4) {
return (a+b) * c;
}
}