本节内容

1.方法的由来;

2.方法的定义与调用;

3.构造器(一种特殊的方法);

4.方法的重载(Override);

5.如何对方法进行debug;

6.方法的调用与栈*

*推荐书目:CLR via C#和C# in Depth, 3rd Edition

1.方法的由来

①方法(method)的前身是C/C++语言的函数(function)

方法是面向对象范畴的概念,在非面向对象语言中仍然称为函数。

可以使用C/C++语言做对比。

*当函数以成员的身份出现时我们就叫它方法(始于C++)

②永远都是类(或结构体)的成员

C#语言中函数不可能独立于类(或结构体之外)。

只有作为类(或结构体)的成员时才被称为方法。

而在C++中是可以的,称为“全局函数”。

③是类(结构体)最基本的成员之一

最基本的成员只有两个——字段与方法(成员变量与成员方法),本质还是数据+算法

方法表示类(或结构体)“能做什么事情”。

④为什么需要方法和函数

目的1:隐藏复杂的结构;

目的2:复用(resue,重用);

C++中#include<iostream>

#include "Student.h"//如果是标准类库的话用尖括号,如果是自己定义的则用引号。

2.方法的声明与调用

①声明方法的语法详解

参见C#语言文档(声明/定义不分家);

Parameter全称为”formal parameter”;

形式上的参数,简称”形参”:形式参数参与构成算法的算法逻辑(即在算法中作为变量参与计算);

Parameter是一种变量:形式参数变量;

②方法的命名规范:

大小写规范:pascal法则(每个单词首字母大写);

需要以动词或者动词短语作为名字;

③重温静态(static)方法和实例方法:静态方法是隶属于类的,类的对象不能调用;实例方法(非静态方法)隶属于类的对象,对象可以调用。

④调用方法:方法名后面的圆括号不能省略。

声明函数时”()”里面的是形参;调用函数时”()”里面是实参。

Argument中文C#文档的官方译法为”实际参数”简称”实参”可理解为调用方法时的真实条件。

调用方法时的Argument列表要与定义方法时的parameter列表相匹配,C#是强类型语言,argument是值,parameter是变量,值与变量(个数与数据类型)一定要匹配不然会报错。

3.构造器

构造器(constructor)是类型的成员之一;

狭义的构造器是指“实例构造器”(instance constractor);

如何调用构造器;

声明构造器;

构造器的内存原理;

构造函数的作用为构造类的实例(对象)并初始化。

①当调用默认构造函数时:

如语句:Student stu=new Student();①

Class Student

{

Public int ID;

Public string Name;

}

*由于①语句是在main函数了的,stu引用变量为局部变量,先在栈中分配4个字节的空闲内存;*new操作符创建了Student类的一个实例,通过调用Student();默认构造函数,在堆内存中开辟一块空内存大小为该实例所包含的数据之和的空间存放实例,(int ID;4个字节,string name4个字节)所以分配8个字节的内存空间,由于默认构造函数默认赋值为0,故该块内存里的数据初始值为0;*最后将该内存的首地址转化为2进制数,复制到引用变量stu的栈内存当中。

②当调用有参构造函数时:

第一步和第三步操作与调用默认构造函数时相同;不同之处在于第二步:

&当参数为数值类型时:首先在堆内存上这8字节的实例内存空间里,int类型占4个字节,传进来的实参值为1(假设)则把1(都要转化为2进制)转化为2进制存在该内存里;

&当参数为引用类型时(记住凡是类类型都是引用类型):剩下的4个字节是string类型的存储空间,(假设传进来的实参为”it’OK”)

由于string是类类型的,而类类型是引用类型,所以,这4个字节里面存放的只是引用变量,还要再去堆内存中找一块位置存放实参”it’OK”。找到内存空间后把”it’sOK”这个字符串数据转化为2进制数据存入其中。(最后该内存首地址转化为2进制存在string类型栈内存中与上面一致)

4.方法的重载(Overload)

①调用重载方法的示例;

②声明带有重载的方法

方法签名(method signature)由方法的名称、类型形参(讲泛型的时候会遇到)的个数和它的每一个形参(按从左到右的顺序)的类型和种类(值、引用(ref)或输出(out))组成。方法签名不包含返回值。(主要看方法名和参数列表)

实例构造函数签名由它的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出)组成;

重载决策(到底调用哪一个重载):用于在给定了参数列表和一组候选函数成员的情况下、选择一个最佳函数成员来实施调用。

5.如何对方法进行debug(核心技能)

设置断点(breakpoint);

观察方法调用时的call stack;

Step-in,Step-over,Step-out;

观察局部变量的值与变化。(可以通过局部变量窗口观察,还可以把鼠标放在变量上观察,也可以把鼠标放在变量上出现的小窗口固定住来观察)

调用栈(call stack)和内存栈的关系:比如递归,不断的调用自己,直到有一个停止的值,若没有,则调用栈就会越来越深直到把内存栈占爆了,这时候就stackOverflow(栈溢出)

Step-in(F11)(逐语句):进入方法当中,最细腻的debug手段

Step-over(F10)(逐过程):不走进方法直接跳过去,比较粗犷一些的debug手段

一般为两者结合使用,先用F10快速的大范围的排查是哪个方法出现问题再使用F11走进方法一步一步debug。(怀疑有bug的地方就F11仔细的排查)

Step-out(跳出):作用为跳转到调用断点当前方法的类或方法里面(按顺序)例如3调用2,2调用1,则在1中设置断点,第一次按Shift F11跳到2处,再按一次跳转到3处。

*综合使用这三种方法会使我们具有强大的debug能力。

6.方法的调用与栈

①方法调用时栈内存的分配

对stack frame(一个方法在被调用过程中栈内的布局)的分析

*栈内存由高字节位向低字节位发展,发展到最低限度之后就会Overflow,

例如C#fun中的main函数输出语句依次调用三个方法,调用时,main方法先在栈内存里开辟一个内存空间叫stack frame(栈帧)。

方法的调用关系有调用和被调用,调用者叫做Caller,被调用者叫做Callee,那么问题来了比如main函数中调用其他函数: Console.WriteLine(c.GetConeVolume(100, 100));那么传进去的两个参数(100)哪个函数来管理呢,不同的语言规定不同,C#是按C++的标准,参数归主调者(caller)管,就是这里的main管。在栈内存中分别开辟参数相应类型大小的空间,先压哪个参数进去呢?不同的语言规定不同,C#遵从C++的规则先左后右,谁调用谁负责把参数压进栈里故该片内存也是由main管(也是main函数的stack frame),*即方法运行时都先在栈内开辟stack frame内存空间 再把方法内包含的数据都压进该片栈内存中。现在开始方法的调用,遵循谁调用谁压栈的原则,即使方法内无局部变量该方法也会有stack frame(存放方法返回值地址等),方法的返回值是存在cpu的寄存器(学汇编时有讲到)里面的。

*一个方法运行完的出结果返回了值之后,相应的stack frame(栈帧)就会被清空,相应的函数(方法)调用结束相关参数没有用了其在栈帧中的内存也会被清空。(可以联想汇编语言的压栈与出栈)

*这里也可以解释一下overflow,就是因为异常方法一直调用,一直

开辟栈帧,没有一层层的返回,相应参数只进栈不出栈,直至开辟空间到栈顶造成“栈溢出”这就是栈溢出的原理。

C#方法的定义、调用与调试的更多相关文章

  1. JavaSE基础篇—流程控制语句—方法的定义 调用和重载

    1.定义方法 是封装在一起来执行操作语句的集合,用来完成某个功能操作,简单的说就是提取出来的有特定功能的代码(程序).在某些语言中被称为函数或者过程,比较特殊的方法是main方法(主方法),main方 ...

  2. DLL DEF文件编写方法 VC++ 调用、调试DLL的方法 显式(静态)调用、隐式(动态)调用

    DLL 文件编写方法: 1.建立DLL工程 2.声明.定义要导出的函数 BOOL WINAPI InitDlg( HWND hTabctrl,TShareMem* pTshare,CRect* prc ...

  3. day07什么是方法、方法的定义、方法的调用

    复习 1.数组 1)什么是数组 数组就是一种能够保存 多个相同数据类型的数据的变量 2)为什么使用数组 3)数组的构成 3.1)数组名 3.2)数组元素 3.3)数组长度 3.4)数组下标 4)数组的 ...

  4. java 方法的定义与调用

    /* 定义一个方法的格式: public static void 方法名称(){ 方法体 } 方法名称的命名规则和变量一样,使用小驼峰 方法体:也就是大括号里面的可以包含任何语句 注意事项: 1.方法 ...

  5. java 方法定义 调用

    一.定义 格式: 修饰符 返回值类型 方法名(参数){ return } 相比之下python方法的定义简单多了 public static 是修饰符 二.调用 方法名(); 注意:要在main方法中 ...

  6. Vue——项目中接口返回值为函数回调,回调函数定义方法(Vue的方法给原生调用)

    在接口调用中,有时会返回给我们一个函数回调,来自动执行我们在前端定义好的某个函数(多出现于通过回调的方式传递某个数值).在原生项目中,我们只要提供一下这个方法就好了,通过函数回调会自动执行.问题就出现 ...

  7. 泛型方法或泛型类中的方法是内部调用、PInvoke 或是在 COM 导入类中定义的。

    泛型基类中引用Api函数定义时static extern,在子类中会提示: 未处理TypeLoadException 泛型方法或泛型类中的方法是内部调用.PInvoke 或是在 COM 导入类中定义的 ...

  8. Java方法的定义以及调用、方法重载、可变参数以及递归

    目录 何谓方法 方法的定义及调用 方法的定义 方法调用 方法重载 命令行传参 可变参数 递归 何谓方法 Java方法是语句的集合,它们在一起执行一个功能 方法是解决一类问题的步骤的有序组合 方法包含于 ...

  9. java_方法的定义、调用、重载

    方法的定义 1 概述 方法:就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能. 当我们需要这个功能的时候,就可以去调用.这样即实现了代码的复用性,也解决了代码冗余的现象. 2 ...

随机推荐

  1. Day 6 文件属性与命令执行流程

    1. 第一列第一个字符 表示文件类型 rw-r--r--     权限(下周) 4 这个文件被链接次数 root 文件的拥有者(用户) root 文件的拥有组(用户组 ==>家族) 2018 文 ...

  2. IO流 - 字节输入输出流,文件的复制

    IO流 I:input - 输入(读取),eg:把硬盘的内容读取到内存 O: output - 输出(写入) eg:把内存中的东西写入硬盘保存 流:数字(字符/字节) 一般1个字符=2Byte,1By ...

  3. [C++]类的设计(2)——拷贝控制(拷贝控制和资源管理)

      1.类的行为分类:看起来像一个值:看起来想一个指针.     1)类的行为像一个值,意味着他应该有自己的状态.当我们拷贝一个像值的对象时,副本和原对象是完全独立的.改变副本不会对原有对象有任何影响 ...

  4. Anaconda、TensorFlow安装和Pycharm配置详细教程,亲测有效!

    目录 1.Anaconda下载与安装 2.Anaconda安装成功与否测试 3.安装python 4.检查TensorFlow环境添加成功与否 5.TensorFlow安装 6.测试TensorFlo ...

  5. 【面试题】Java基础部分面试题

    Java基础面试题 Equals与==的区别 使用==比较原生类型如:boolean,,int,char等等,  使用equals()比较对象. 1.  ==是判断两个变量或类型是不是指向同一个内存空 ...

  6. 关于CDH集群spark的三种安装方式简述

    一.spark的命令行模式 1.第一种进入方式:执行 pyspark进入,执行exit()退出 注意报错信息:java.lang.IllegalArgumentException: Required ...

  7. js初学总结

    基础 交换变量方式 //利用第三方变量进行交换 var num1 = 10; var num2 = 20; var temp; temp = num1; num1 = num2; num2 = tem ...

  8. 【SQL基础】char,nchar,vchar,nvchar之间的区别

    (1)       定义: char:    固定长度,存储ANSI字符,不足的补英文半角空格. nchar:   固定长度,存储Unicode字符,不足的补英文半角空格 varchar:  可变长度 ...

  9. js中对于数组的操作

    let myArray=[11,22,33]; console.log('原数组:',myArray); myArray.push(44,55); console.log('用push在数组后面插入元 ...

  10. Java 学习笔记之 Suspend和Resume

    Suspend和Resume: Suspend和Resume使用方法: 以下例子证明了线程确实被暂停了,而且还可以恢复成运行状态. public class SuspendResumeThread e ...