CSharp(C#)语言_第三章(方法)

3.1 方法的结构

        方法是一块具有名称的代码,可以使用方法的名称从别的地方执行代码,也可以把数据传入方法并接收数据输出

        方法是类的函数成员,方法有两个主要部分:方法头方法体

方法头指定方法的特征,包括:
        方法是否返回数据,如果返回,返回什么类型
        方法的名称
        哪种类型的数据可以传入方法或返回方法,已经应如何处理这些数据

方法体包含可执行代码的语句序列,执行过程从方法体的第一条语句开始,一直到整个方法结束

3.2 方法体内部代码的执行

        方法体是一块,由大括号括起来的语句序列 ,可以包含以下项目

        本地变量
        控制流结构
        方法调用
        内嵌的块

3.3 本地变量

        本地变量经常是用于保存本地的或临时的计算数据

本地变量的存在性和生存期仅限于创建它的块及其内嵌的块
        它从声明它的那一点开始存在
        它在块完成执行时结束存在
可以在方法体内任意位置声明本地变量,但必须在使用它们之前声明

3.3.1 var关键字

        var关键字并不是特定类型变量的符号。它只是句法上的速记,表示任何可以从初始化语句的右边推断出的类型。在第一个声明中,它是int的速记;在第二个声明中,它是MyExcellentClass的速记。前文中使用显式类型名的代码片段和使用var关键字的代码片段在语义上是等价的

使用var关键字有一些重要的条件:
        只能用于本地变量,不能用于字段
        只能在变量声明中包含初始化时使用
        一旦编译器推断出变量的类型,它就是固定且不能更改的

3.3.2 嵌套块中的本地变量

方法体内部可以嵌套其他的块
        可以有任意数量的块,并且它们既可以是顺序的也可以更深层嵌套的。块可以嵌套到任何级别
        本地变量可以在嵌套块的内部声明,并且和所有的本地变量一样,它们的生存期和可见性仅限于声明它们的块及其内嵌块

3.4 本地常量

        本地常量很像本地变量,只是一旦被初始化,它的值就不能改变了。如同本地变量,本地常量必须声明在块的内部

常量的两个最重要的特征如下:
        常量在声明时必须初始化
        常量在声明后不能改变

常量的核心声明如下所示。语法与字段或变量的声明相同,除了下面内容
        在类型之前增加关键字const
        必须有初始化语句。初始化值必须在编译期决定,通常是一个预定义简单类型或由其组成的表达式。它还可以是null引用,但它不能是某对象的引用,因为对象的引用是在运行时决定的

3.5 控制流

        方法包含了大部分组成程序行为的代码。剩余部分在其他的函数成员中,如属性和运算符
        术语控制流指的是程序从头到尾的执行流程。默认情况下,程序执行持续地从一条语句到下一条语句,控制流语句允许你改变执行的顺序

    选择语句 这些语句可以选择哪条语句或语句块来执行
        ■ if 有条件地执行一条语句
        ■ if…else 有条件地执行一条或另一条语句
        ■ switch 有条件地执行一组语句中的某一条

    迭代语句 这些语句可以在一个语句块上循环或迭代
        ■ for 循环——在顶部测试
        ■ while 循环——在顶部测试
        ■ do 循环——在底部测试
        ■ foreach 为一组中每个成员执行一次

    跳转语句 这些语句可以让你从代码块或方法体内部的一个地方跳到另一个地方
        ■ break 跳出当前循环
        ■ continue 到当前循环的底部
        ■ goto 到一个命名的语句
        ■ return 返回到调用方法继续执行

3.6 方法调用

        可以从方法体的内部调用其他方法

英文中call(调用)方法和invoke方法是同义的
调用方法时要使用方法名并带上参数列表

调用方法时的动作顺序
(1)当前方法的执行在调用点被挂起
(2)控制转移到被调用方法的开始
(3)被调用方法执行直到完成
(4)控制回到发起调用的方法

3.7 返回值

        方法可以向调用代码返回一个值。返回的值被插入到调用代码中发起调用的表达式所在的位置
        ■ 要返回值,方法必须在方法名前面声明一个返回类型
        ■ 如果方法不返回值,它必须声明void返回类型

3.8 返回语句和 void方法

        void方法不需要返回语句。当控制流到达方法体的关闭大括号时,控制返回到调用代码,并且没有值被插入到调用代码中。
        不过,当特定条件符合的时候,我们常常会提前退出方法以简化程序逻辑
        可以在任何时候使用下面形式的返回语句退出方法,不带参数
                return;
        这种形式的返回语句只能用于用void声明的方法

3.9 参数

        方法是可以被程序中很多地方调用的命名代码单元,它能把一个值返回给调用代码。返回一个值的确有用,但如果需要返回多个值呢?还有,能在方法开始执行的时候把数据传入方法也会有用。参数就是允许你做这两件事的特殊变量

3.9.1 形参

        形参是本地变量,它声明在方法的参数列表中,而不是方法体中
        因为形参是变量,所以它们有类型和名称,并能被写入和读取
        和方法中的其他本地变量不同,参数在方法体的外面定义并在方法开始之前初始化(但有一种类型例外,称为输出参数)
        参数列表中可以有任意数目的形参声明,而且声明必须用逗号隔开
形参在整个方法体内使用,在大部分地方就像其他本地变量一样

3.9.2 实参

        当代码调用一个方法时,形参的值必须在方法的代码开始执行之前被初始化
        用于初始化形参的表达式或变量称作实参(actual parameter,有时候也称argument)
        实参位于方法调用的参数列表中
        每一个实参必须与对应形参的类型相匹配,或是编译器必须能够把实参隐式转换为那个类型
        当方法被调用的时候,每个实参的值都被用于初始化相应的形参,方法体随后被执行

        实参的数量必须和形参的数量一致,并且每个实参的类型也必须和所对应的形参类型一致。这种形式的参数叫做位置参数

3.10 值参数

        参数有几种,各自以略微不同的方式从方法传人或传出数据。你到现在一直看到的这种类型是默认的类型,称为值参数(value parameter)
        使用值参数,通过将实参的值复制到形参的方式把数据传递给方法。方法被调用时,系统做如下操作:
        ■ 在栈中为形参分配空间
        ■ 将实参的值复制给形参
值参数的实参不一定是变量。它可以是任何能计算成相应数据类型的表达式
在把变量用作实参之前,变量必须被赋值。对于引用类型,变量可以被设置为一个实际的引用或null

3.11 引用参数

第二种参数类型称为引用参数
        ■使用引用参数时,必须在方法的声明和调用中都使用ref修饰符
        ■实参必须是变量,在用作实参前必须被赋值。如果是引用类型变量,可以赋值为一个引用或null

        对于值参数,系统在栈上为形参分配内存,相反,引用参数具有以下特征
        ■ 不会为形参在栈上分配内存
        ■ 实际情况是,形参的参数名将作为实参变量的别名,指向相同的内存位置
        由于形参名和实参名的行为就好像指向相同的内存位置,所以在方法的执行过程中对形参作的任何改变在方法完成后依然有效(表现在实参变量上)

3.12 引用类型作为值参数和引用参数

        在前几节中我们看到了,对于一个引用类型对象,不管是将其作为值参数传递还是作为引用参数传递,我们都可以在方法成员内部修改它的成员。不过,我们并没有在方法内部设置形参本身。本节来看看在方法内设置引用类型形参时会发生什么
        ■ 将引用类型对象作为值参数传递 如果在方法内创建一个新对象并赋值给形参,将切断形参与实参之间的关联,并且在方法调用结束后,新对象也将不复存在
        ■ 将引用类型对象作为引用参数传递 如果在方法内创建一个新对象并赋值给形参,在方法结束后该对象依然存在,并且是实参所引用的值

3.13 输出参数

输出参数用于从方法体内把数据传出到调用代码,它们的行为与引用参数非常类似。如同引用参数,输出参数有以下要求
        ■ 必须在声明和调用中都使用修饰符。输出参数的修饰符是out而不是ref
        ■ 和引用参数相似,实参必须是变量,而不能是其他类型的表达式。这是有道理的,因为方法需要内存位置保存返回值

        与引用参数类似,输出参数的形参担当实参的别名。形参和实参都是同一块内存位置的名称。显然,方法内对形参的任何改变在方法执行完成之后通过实参变量都是可见的

        与引用参数不同,输出参数有以下要求
        ■ 在方法内部,输出参数在能够被读取之前必须被赋值。这意味着参数的初始值是无关的,而且没有必要在方法调用之前为实参赋值
        ■ 在方法返回之前,方法内部贯穿的任何可能路径都必须为所有输出参数进行一次赋值因为方法内的代码在读取输出变量之前必须对其写入,所以不可能使用输出参数把数据传入方法。事实上,如果方法中有任何执行路径试图在输出参数被方法赋值之前读取它,编译器就会产生一条错误信息

3.14 参数数组

        参数类型都必须严格地一个实参对应一个形参。参数数组则不同,它允许零个或多个实参对应一个特殊的形参。参数数组的重点如下:

        ■ 在一个参数列表中只能有一个参数数组
        ■ 如果有,它必须是列表中的最后一个
        ■ 由参数数组表示的所有参数都必须具有相同的类型。

声明一个参数数组必须做的事如下:
        ■ 在数据类型前使用params修饰符
        ■ 在数据类型后放置一组空的方括号

类型名后面的空方括号指明了参数是一个整数数组
        ■ 数组是一组整齐的相同类型的数据项
        ■ 数组使用一个数字索引进行访问
        ■ 数组是一个引用类型,因此它的所有数据项都保存在堆中

3.15 方法重载

一个类中可以有一个以上的方法拥有相同的名称,这叫做方法重载(method overload)
使用相同名称的每个方法必须有一个和其他方法不相同的签名(signature)
    方法的签名由下列信息组成,它们在方法声明的方法头中:
        ■ 方法的名称
        ■ 参数的数目
        ■ 参数的数据类型和顺序
        ■ 参数修饰符
    返回类型不是签名的一部分,而我们往往误认为它是签名的一部分
形参的名称也不是签名的一部分

3.16 命名参数

        至今我们所有用到的参数都是位置参数,也就是说每一个实参的位置都必须与相应的形参位置一一对应
        此外,C#还允许我们使用命名参数(namedparameter)。只要显式指定参数的名字,就可以以任意顺序在方法调用中列出实参
        ■ 方法的声明没有什么不一样。形参已经有名字了
        ■ 不过在调用方法的时候,形参的名字后面跟着冒号和实际的参数值或表达式

在调用的时候,你可以既使用位置参数又使用命名参数,但如果这么做,所有位置参数必须先列出来

3.17 可选参数

        C#还允许可选参数(optional parameter)。所谓可选参数就是我们可以在调用方去的时候包含这个参数,也可以省略它

3.18 栈帧

        在调用方法的时候,内存从栈的顶部开始分配,保存和方法关联的一些数据项。这块内存叫做方法的栈帧(stackframe)

栈帧包含的内存保存如下内容:
    ■返回地址,也就是在方法退出的时候继续执行的位置
    ■这些参数分配的内存,也就是方法的值参数,或者还可能是参数数组(如果有的话)
    ■各种和方法调用相关的其他管理数据项

    在方法调用时,整个栈帧都会压入栈。
    在方法退出的时候,整个栈帧都会从栈上弹出。弹出栈帧有的时候也叫做栈展开
(unwind)

3.19 递归

方法调用自身,叫做递归

发布了48 篇原创文章 · 获赞 55 · 访问量 4466

猜你喜欢

转载自blog.csdn.net/qq_43562262/article/details/104854721