方法
方法又称函数,本质是具有名称的代码块。 方法是对象或类可执行的计算或操作。方法是封装代码进行重复使用的一种机制,可以封装代码,简化代码,提高可读性,增加代码复用性,降低冗余度,抽象行为。方法只能在类或结构体中声明,通常仅负责单一功能。
方法声明通常包括修饰符、返回值类型、方法名、参数列表(可选)、方法体。每个方法声明都为每个输入参数和返回值指定名称、类型和种类(值、引用或输出)。
- 修饰符用于修饰方法以确定可访问性、是否为抽象/虚/重写方法等。
- 返回类型用于指定方法返回给调用者的结果的类型,无返回结果时为
void
。返回结果需要接收或处理。 - 方法名采取Pasacl命名法,要求见名知意。
- 参数列表表示在调用方法时需要传递的形式参数(调用者给的为实际参数),多个以
,
分隔。调用时需按定义顺序依次传递,个数、类型必须匹配。 - 方法体指定了在调用方法时执行的语句。方法体可包含零或多条语句,必须书写
{}
。可以使用return
在方法体内任何位置终止方法体的执行,有返回值时return
后需要跟返回结果。当方法主体是单个表达式时,可使用Lambda表达式简写。
public string ToString() => "This is an object";
// 等价于
public string ToString() { return "This is an object"; }
通过方法名调用方法,并提供所需参数。
public void Print(string content)
{
Console.WriteLine(content);
}
Print(ToString());
方法体内声明的仅于内部使用的变量为局部变量。局部变量声明指定了类型、变量名以及可能的初始值,仅在最近的{}
范围内可用。C#要求局部变量必须初始化才能获取其值。
方法参数
传递给方法的参数有四类:值参数、引用参数、输出参数和参数数组。此外,C#支持命名参数和可选参数。
值参数传递参数存储的内容,值类型传值,引用类型传引用。值参数是局部变量,从为其传递的实参中获取初始值。
public int Max(int a, int b) => a >= b ? a : b;
public int Max(int[] array)
{
int count = array.Length;
if (array == null || count == 0) return 0;
int max = array[0];
for (int i = 1; i < count; i++)
{
max = Max(max, array[i]);
}
return max;
}
引用参数以ref
声明,会按引用传递参数,使得形参在方法内部被修改时,实参也随之改变。调用时引用参数必须已显式赋值。通常用于在方法内部修改原变量值。
public void ChangeValueRef(ref int value)
{
value = 0;
}
int a = 10;
ChangeValueRef(ref a); // 值类型a的值在方法ChangeValueRef()中被改变
输出参数以out
声明,会按引用传递参数,使得实参在方法内部被赋值。调用时实参不需要调用者提前赋值,但在方法内部返回时必须赋值。通常用于从方法返回多个结果。
public void GetValueOut(out int value)
{
value = 0;
}
int a;
GetValueOut(out a); // 值类型a的值在方法GetValueOut()中被改变
参数数组(变长参数)以params
声明,允许向方法传递数量不定的同类型参数。参数数组只能是方法的最后一个参数,且参数数组的类型必须是一维数组类型。 在调用包含形参数组的方法时,要么传递形参数组类型的一个实参,要么传递形参数组的元素类型的任意数量实参(数组实例会自动创建,并初始化为包含给定的自变量)。通常用于简化调用。
public void WriteLine(string fmt, params object[] args) { }
Console.WriteLine("x={0}, y={1}", 1, 2);
命名参数是在传参时通过形参名指定参数,而无需按形参顺序传参。 通过对形参命名还能标识每个参数的含义,提高代码可读性。只有命名参数是最后一个或者按顺序传参时才能不对全部参数命名。
public void PrintOrderDetails(string seller, int orderNum, string product) { }
// 按顺序传参
PrintOrderDetails("Gift Shop", 31, "Red Mug");
// 通过命名参数可以不按循序传参
PrintOrderDetails(product: "Red Mug", seller: "Gift Shop", orderNum: 31);
// 仅在两种情况下才能不对全部参数命名
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug"); // 仅命名最后一个参数
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); // 按顺序传参
可选参数是在参数列表中给参数赋默认值的参数,此时在外部调用时可选择是否传入该参数。支持多参数默认值,可选参数必须写在非可选参数之后。
public void SetValue(int[] array, int value, bool isSetAll = true)
{
if (array == null || array.Length == 0) return;
array[0] = value;
if (isSetAll)
{
int count = array.Length;
for (int i = 1; i < array.Length; i++)
{
array[i] = value;
}
}
}
int[] array = { 1, 2, 3 };
SetValue(array, 0);
重载
在同一语句块中,方法名称相同,参数列表不同,即重载。 重载与返回值类型无关,只与参数的类型、数量、顺序有关。ref
、out
和params
修饰的参数也可以引起重载。调用时,程序会根据传入的参数列表判断使用哪一个方法。
public int Sum(int a, int b) => return a + b;
public int Sum(int a, int b, int c) => return a + b + c;
public float Sum(float a, float b) => return a + b;
public float Sum(int a, float b) => return a + b;
public float Sum(float a, int b) => return a + b;
重载可以为一组功能相似的方法(不同类型参数的同一类型行为)统一命名以减少方法名数量,达到降低调用成本、防止命名空间污染、提高程序的可读性。
递归
递归即让函数自己调用自己。
public void Function()
{
Function();
}
一个正确的递归函数必须有结束调用的条件,并且该条件必须改变以到达终止递归的目的。
// 例:求一个数n的阶乘
public int GetFactorial(int a)
{
if (a < 0) throw new ArgumentException();
if (a == 0 || a == 1) return 1;
return a * GetFactorial(a - 1);
}
递归简化了代码逻辑,但增加了方法调用开销。