方法
方法的构成
一个方法由签名和方法体构成。其中,方法的签名包括方法的名称以及参数信息(包括形参的修饰符、数目、类型以及泛型参数的数目)。特别需要注意的是,返回值类型、形参和类型参数名称并不属于方法签名的一部分。
public int Add(int a, int b)
{
return a + b;
}
其中形参列表中的a和b, public和返回值int并不属于方法签名, Add(int, int)才是方法签名
参数
命名和可选参数
public int Add(int a, int b = 1)
{
return a + b;
}
int result1 = Add(1, 2); //3
int result2 = Add(1); //2
可选参数的规则:
- 可选参数不能为参数列表第一个参数, 它必须位于所有必选参数之后
- 可选参数必须指定一个默认值
- 可选参数的默认值必须是一个常量表达式,不能为变量
- 所有可选参数以后都必须为可选参数
命名参数示例
public int GetArea(int height, int width)
{
return height * width;
}
int result = GetArea(width: 2, height: 3); //参数顺序无关
重载决策机制
M(string s, int i = 1);
M(object o);
M(int i, string s = "Hello");
M(int i);
M(5);
判断规则
- 如果所有参数要么都可选, 要么有一个和参数类型兼容的参数(根据名称或位置)
- 如果有多种选择, 重载决策机制优先选择为指定了具体值的重载, 而忽略那些没有为可选参数提供值的情况
- 如果有两种选择待选, 则优先选择没有省略可选参数的重载
M(string, int)
被淘汰, 实参5不能被隐匿转换为string类型M(int, string)
符合条件, 是待选之一, 它的第二个参数是可选的M(object) M(int)
也是待选的重载M(int, string) M(int)
要优于M(object)
, 因为5到int的转换要好于5到object的转换M(int)
要优于M(int, string)
, 因为没有可选参数被省略M(int)
最后被使用
四种类型的参数
按值传递参数
值参数是通过将实参的值复制到形参,来实现将值传递到方法,也就是我们通常说的按值传递。方法被调用时,CLR会
- 在托管堆栈中为形参分配空间
- 将实参的值复制到形参
形参为值类型时是将实参中的值(基本数据)复制到新的空间中,形参为引用类型时是将实参中的值(地址)复制到新的空间。
按引用传递参数--关键字(ref)
引用参数,也就是说,传递的是参数的引用而不是参数值
public void DoSomething(ref int someValue)
{
someVaule = 10;
}
int x = 5;
DoSomething(ref x);
输出参数--关键字(out)
输出参数将值从方法内传递到方法外, 只有变量才有资格作为输出参数,文本值和表达式都不可以
int x = 5;
string s = “yy”;
DoSomething(ref x, out s);
Console.WriteLine(“x={0}, s={1}”, x, s);
public void DoSomething(ref int value1, out string value2)
{
value1 = 10;
value2 = “xx”;
}
针对引用传递参数和输出参数, 编译器允许在方法中的任意位置、任意时刻读取引用参数的值, 但禁止在为输出参数赋值前读取它。
参数数组--关键字(params)
参数数组类似于可选参数, 但也大有不同, 参数数组更加灵活
public void DoSomething(string str, params int[] values){}
DoSomething(“a”);
DoSomething(“a”, 1);
DoSomething(“a”, 1, 2);
int[] arr = { 1, 2, 3};
DoSomething(“a”, arr);
栈帧
栈帧也叫做过程活动记录, 是编译器用来实现方法调用的一种数据结构, 函数的调用堆栈包含:方法参数, 方法中的局部变量, 方法执行完后的返回地址, 获取文件中包含执行代码的行号和列号, 获取包含所执行代码的文件名
递归
递归的能力在于用有限的语句来定义对象的无限集合. 递归就是在方法里调用自身, 在使用递归策略时, 必须有一个明确的递归结束条件, 称为递归出口, 否则将无限进行下去.
使用递归程序的优点: 用递归的思想写出的程序往往十分简洁易懂
使用递归程序的缺点: 1.运行效率低, 2. 在递归调用的过程中,系统会为每一次调用生成新的栈帧,并使用栈来存储,因此递归次数过多容易造成栈溢出
方法的重载
在类中定义多个名称相同、签名(方法名、参数类型及个数、参数顺序及修饰符)不同的方法。需要注意的是,方法的返回值不属于签名的一部分。所以是否构成重载有以下几个条件:
1.在同一个类中 2.方法名相同 3.方法签名不同
静态方法
方法主要分为静态方法和实例方法,使用了static修饰符的方法为静态方法, 静态方法有如下特点:
- 它不属于特定对象的方法, 它可以被一个类的具体实例访问
- 它只可以访问静态成员变量, 而不可以直接访问实例变量
- 它不用创建类的对象即可访问
静态方法中不能使用this关键字引用类的当前实例
参考引用
[1]: C# 权威指南