版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/manofstyle1/article/details/39156353
————————————————
版权声明:本文为CSDN博主「人生不再重来」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dushuyang/article/details/39156353
随笔中添加个人简介,如若错误,望提出指正.谢谢!
方法的结构
本质上,方法是一块具有名称的代码。可以使用方法的名称执行代码,也可以把数据传入方法并接收数据输出。
方法是类的函数成员。方法有两个主要部分,方法头和方法体。//或者方法名和执行体
方法头指定方法的特征,包括:
方法是否返回数据,如果返回,返回什么类型;方法的名称;什么类型的输入可以传入方法。方法体包含可执行代码的语句序列。执行从方法体的第一条语句开始,一直到整个方法结束。//在执行方法中默认为“{”开始“}”结束的,但是如果执行体中进行提前结束方法体也是可行的方案 ,比如return语句结束方法体。
方法内部的代码执行
方法体是一个块,是大括号括起的语句序列。块可以包含以下项目:
本地变量控制流结构方法调用内嵌的块5.2 本地变量
和字段一样,要地变量也保存数据。字段通常保存和对象状态有关的数据,而本地变量用于保存本地的或临时的计算数据。
本地变量的存在性仅限于创建它的块及其内嵌的块。
它从声明它的那一点开始存在。它在块完成执行时结束存在。可以在方法体内任意位置声明本地变量。
对比实例字段和本地变量
实例字段
本地变量
生存期
从实例被创建时开始直到实例不再被访问时结束
从它在块中被声明的那点开始在块完成结束
隐式初始化
初始化成该类型的默认值
没有隐式初始化,如果变量在使用之前没有被赋值,编译器会产生一条错误信息
存储区域
类的所有字段都存储在堆里,无论它们是值类型的还是引用类型的。
值类型:存储在栈里
引用类型:引用存储在栈里,数据存储在堆里
类型推断和var关键字
var关键字并不是某种特别类型的符号。它只是句法上的速记,表示任何可以从初始化的右边推断出的类型。
使用var关键字有一些重要的条件:
只能用于本地变量,不能用于字段。只能在变量声明中包含初始化时使用。一旦编译器推断出类型,它就是固定且不能更改的。
var关键字不像JavaScript的var那样可以引用不同的类型。它是从等号右边推断出的实际类型的速记。var关键字并不改变C#的强类型性质。
嵌套块中的本地变量
方法体内部可以嵌套其他的块。
可以有任意数量的块,并且它们即可以是顺序的也可以更深层嵌套的。块可以嵌套到任何级别。本地变量可以在嵌套块的内部声明,并且和所有的本地变量一样,它们的生存期仅限于声明它们的块及其内嵌块。说明:在C和C++中,可以先定义一个本地变量,然后在嵌套块中定义另一个相同名称的本地变量。在内部范围,内部名称掩盖了外部名称。然而,在C#中不管嵌套级别如何,都不能在第一个名称的有效范围内声明另一个同名的本地变量。
5.3 本地常量
本地常量很像本地变量,只是一旦它被初始化,它的值就不能被改变。
常量的两个最重要的特征如下:
常量在声明中必须初始化常量在声明后不能改变在类型之前增加关键字const。必须有初始化语句。初始化值必须在编译期决定,通常是一个预定义简单类型或由其组成的表达式。它还可以是null引用,但它不能是某对象的引用,因为对象在引用是在运行时决定的。说明:关键字const不是一个修饰符,而是核心声明的一部分。它必须直接放在类型的前面。
5.4 控制流
术语控制流指的是程序从头到尾的执行流程。默认情况下,程序执行持续地从一条语句到下一条语句,控制语句允许你改变执行的顺序。
选择语句:选择哪条语句或语句块来执行
这些都是在方体中最为常见的一些语句:
if:有条件地执行一条语句;if...else:有条件地执行一条或另一条语句;switch:有条件执行一组语句中的一条。迭代语句:在一个语句块上循环或迭代
for:循环—在顶部测试;while:循环——在顶部测试;do:循环——在顶部测试;foreach:为一组中每个成员执行一次。跳转语句:从块或方法体内部的一个地方跳到另一个地方。
break:跳出当前循环;continue:到当前循环的底部;goto:到一个命名的语句;return:返回到发起调用的方法。
5.5 方法调用
可以从方法的内部调用其他方法。同样也可进行内部调用自身,
英文中call(调用)方法和invoke方法是同义的。调用方法时要使用方法名并带上参数列表。
5.6 返回值
方法可以向调用代码返回一个值。返回的值被插入到调用代码中发起调用的表达式所在的位置。
要返回值,方法必须在方法名前面声明一个返回类型。如果方法不返回值,它必须声明void返回类型。
返回语句包括关键字return及其后面的表达式。每一条穿过方法的路径都必须以一条这种形式的return语句结束。
返回语句和void方法
当方法有返回值是需要表明需要返回的类型,方法体内会自行判断返回类型是否一致,如若不一致将语句错误。
void方法不需要返回语句。当控制流到达方法体的关闭大括号时,控制返回到调用代码,并且没有值被插入到调用代码中。
不过,当特定条件符合的时候,会提交退出方法以简单程序逻辑。
可以在任何时候使用下面形式的返回语句退出方法,不带参数:return;这种形式的返回语句只能用于声明为void类型的方法。
5.7 参数
调用命名代码单元,它能把一个值返回给调用代码。返回一个值的确有用,但如果需要返回多个值呢?还有,能在方法开始执行的时候把数据传入方法也会有用。参数就是允许你做这两件事的特殊变量。
形参
形参是声明在方法的参数列表中而不是方法体中的本地变量。
形参是变量,它们有类型和名称,并能被写入和读出。和方法中的其他变量不同,参数在方法体的外面定义并在方法开始之前初始化。但有一种类型例外。参数列表中可以有任意数目的形参声明,而且声明必须用逗号隔开。
实参
当代码调用一个方法时,形参的值必须在方法开始执行之前被初始化。
用于初始化形参的表达式或变量称为实参。实参放在方法调用的参数列表中。当方法被调用的时候,每个实参的值都被用于初始化相应的形参,方体随后被执行。
调用方法时,必须满足下列要求:
实参的数目必须和形参的数目相同,(有一种情况例外)每个实参必须和相应形参的类型匹配
值参数
有几种参数,它们使用稍微不同的方法从方法传入或传出数据。你到现在一直看到的这种类型是默认的类型,称为值参数。
使用值参数,数据通过复制实参的值到形参的方式传递到方法。方法被调用时,系统做如下操作:
在栈中为形参分配空间。复制实参到形参。
引用参数
第二种参数类型称为引用参数。
使用引用参数时,必须在方法的声明和调用中都使用ref修饰符。实参必须是变量,在用作实参前必须被赋值。如果是引用类型变量,可以赋值为一个引用或值。
记住,对于值参数,系统在栈里为形参分配内存。相应地,引用参数有以下特征:
不在栈中为形参分配新的内存。形参的名称相当于实参变量的别名,引用与实参相同的内存位置。
即然形参名和实参名引用相同的内存位置,显然,在方法执行期间对形参所做的任何改变在方法完成之后通过实参变量都是可见的。
输出参数
输出参数用于从方法体内把数据传出到调用代码,它们非常类似引用参数。如同引用参数,输出参数有以下要求:
必须在声明的调用中都使用修饰符。输出参数的修饰符是out而不是ref。实参必须是变量,不能是其他表达式类型。
就像引用参数,输出参数的形参担当实参的别名,形参和实参都是同一内在位置的名称。显然,方法内对形参的任何改变在方法之后通过实参都是可见的。
与引用参数不同,输出参数有以下要求:
在方法内部,输出参数在被读取之前必须被赋值。这意味着参数的初始值是无关的,而且没有必须在方法调用之前为实参赋值。每个输出参数在方法返回之前必须被赋值。因为方法内的代码在读出输出变量之前必须对其写入,所以不可能使用输出参数把数据传入方法。事实上,如果方法中有任何执行路径试图在输出参数被赋值之前读取它,编译器就会产生一条错误信息。
参数数组
至此,以上所述的参数类型都必须严格地一个实参对应一个形参。参数数组不一样,它允许零个或多个实参对应一个特殊的形参。参数数组的重点如下:
在一个参数列表中只能有一个参数数组。如果有,它必须是列表中的最后一个。
声明一个参数数组必须做的事:
在数据类型前使用params修饰符。在数据类型后入围一组空的方括号。下面的方法头展示了int型参数数组的声明语法。在这个示例中,形参inVals可以代表零个或多个int实参。
void ListInts(params int[] inVals)
方法的调用
有两个方法提供实参,可以使用如下的形式:
一个逗号分隔的该数据类型元素的列表。所有元素必须是方法声明中指定的类型。 ListInts(10,20,30);一个该数据类型的一维数组 int[] intArray={1,2,3}; ListInts(intArray);
请注意,在这些示例中,并不在调用时候用params修饰符。参数数组中修饰符的使用并不适用其他参数类型的模式。
其他参数类型要么使用修饰符,要么不使用修饰符。
值参数的声明和调用都不带修饰符。引用参数和输出参数在两个地方都需要修饰符。然而参数数组:
在声明中需要修饰符。在调用中不允许有修饰符。 延伸式
方法调用的第一种形式有时被称为延伸式,这种形式在调用中使用分享的实参。
在使用一个为参数数组分享实参的调用时,编译器做下面的事:
接受实参列表,用它们在堆中创建并初始化一个数组。把数组的引用保存到栈里的形参里。如果在对应的形参数组的位置没有实参,编译器会创建一个有零个元素的数组来使用。
关于参数数组,需要记住的重要一点是当数组在堆中被创建时,实参的值被复制到数组中。在这方面,它们像值参数。
如果数组是值类型,那么值被复制,实参不受方法内部的影响。如果数组参数是引用类型,那么引用被复制,实参引用的对象可以受到方法内部的影响。
数组作实参
也可以在方法调用之前创建并组装一个数组,把单一的数组变量作为实参传递。这种情况下,编译器使用你的数组而不是重新创建一个。
5.8 栈帧
当一个方法被调用时,在栈顶分配了一块内存用于保存一定数量与方法相关的数据项,这块内存叫方法的栈帧(stack frame)。
栈帧含有保存下列内容的内存:
返回地址——就是方法退出时在哪儿继续执行。分配内存的参数——就是方法的值参数,如果有参数以及参数数组。与方法调用相关的其他各种管理数据项。
方法被调用时,它的整个栈帧被压入栈中。
方法退出时,它的整个栈帧被从栈中弹出。弹出一个栈帧有时也称为释放栈。
5.9 递归
除了调用其他方法,方法还能调用自己,这称为递归(recursion)。
5.10 方法重载
一个类中可以有一个以上的方法拥有相同的名称,这叫做方法重载(method overload)。使用相同名称的每个方法必须有一个和其他方法不相同的签名(signature)。
方法的签名由下列信息组成,它们在方法声明的方法头中:
方法的名称;参数的数目;参数的数据类型和顺序;参数修饰符。返回类型不是签名的一部分,而认它是签名的一部分是一种常见的错误。形参的名称也不是签名的一部分。