C#方法的定义、调用与调试
本节内容
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#方法的定义、调用与调试的更多相关文章
- JavaSE基础篇—流程控制语句—方法的定义 调用和重载
1.定义方法 是封装在一起来执行操作语句的集合,用来完成某个功能操作,简单的说就是提取出来的有特定功能的代码(程序).在某些语言中被称为函数或者过程,比较特殊的方法是main方法(主方法),main方 ...
- DLL DEF文件编写方法 VC++ 调用、调试DLL的方法 显式(静态)调用、隐式(动态)调用
DLL 文件编写方法: 1.建立DLL工程 2.声明.定义要导出的函数 BOOL WINAPI InitDlg( HWND hTabctrl,TShareMem* pTshare,CRect* prc ...
- day07什么是方法、方法的定义、方法的调用
复习 1.数组 1)什么是数组 数组就是一种能够保存 多个相同数据类型的数据的变量 2)为什么使用数组 3)数组的构成 3.1)数组名 3.2)数组元素 3.3)数组长度 3.4)数组下标 4)数组的 ...
- java 方法的定义与调用
/* 定义一个方法的格式: public static void 方法名称(){ 方法体 } 方法名称的命名规则和变量一样,使用小驼峰 方法体:也就是大括号里面的可以包含任何语句 注意事项: 1.方法 ...
- java 方法定义 调用
一.定义 格式: 修饰符 返回值类型 方法名(参数){ return } 相比之下python方法的定义简单多了 public static 是修饰符 二.调用 方法名(); 注意:要在main方法中 ...
- Vue——项目中接口返回值为函数回调,回调函数定义方法(Vue的方法给原生调用)
在接口调用中,有时会返回给我们一个函数回调,来自动执行我们在前端定义好的某个函数(多出现于通过回调的方式传递某个数值).在原生项目中,我们只要提供一下这个方法就好了,通过函数回调会自动执行.问题就出现 ...
- 泛型方法或泛型类中的方法是内部调用、PInvoke 或是在 COM 导入类中定义的。
泛型基类中引用Api函数定义时static extern,在子类中会提示: 未处理TypeLoadException 泛型方法或泛型类中的方法是内部调用.PInvoke 或是在 COM 导入类中定义的 ...
- Java方法的定义以及调用、方法重载、可变参数以及递归
目录 何谓方法 方法的定义及调用 方法的定义 方法调用 方法重载 命令行传参 可变参数 递归 何谓方法 Java方法是语句的集合,它们在一起执行一个功能 方法是解决一类问题的步骤的有序组合 方法包含于 ...
- java_方法的定义、调用、重载
方法的定义 1 概述 方法:就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能. 当我们需要这个功能的时候,就可以去调用.这样即实现了代码的复用性,也解决了代码冗余的现象. 2 ...
随机推荐
- Linux线程唤醒与等待
生产者消费者模式在程序设计中出现频率非常高,经常会有线程间通过消息队列或其他共享变量进行交互的场景.而这时就会出现一个问题,消费者如何知道生产者已经生产了数据呢?有的程序会采取消费者循环判断消息队列大 ...
- Android 正 N 边形圆角头像的实现
卖一下广告,欢迎大家关注我的微信公众号,扫一扫下方二维码或搜索微信号 stormjun94(徐公码字),即可关注. 目前专注于 Android 开发,主要分享 Android开发相关知识和一些相关的优 ...
- vscode中如何自动保存
是的,vscode是个不错的编辑器,它的扩展功能能支持很多的语言,然后在实践过程中,我们发现每写好一次就得手动按CTRL+S,未免有点手酸,这时候我们就可以开启我们的自动保存功能,方式也很简单,在 文 ...
- 面试并发volatile关键字时,我们应该具备哪些谈资?
提前发现更多精彩内容,请访问 个人博客 提前发现更多精彩内容,请访问 个人博客 提前发现更多精彩内容,请访问 个人博客 写在前面 在 可见性有序性,Happens-before来搞定 文章中,happ ...
- SpringBootSecurity学习(11)网页版登录之URL动态权限
动态权限 前面讨论用户登录认证的时候,根据用户名查询用户会将用户拥有的角色一起查询出来,自动实现判断当前登录用户拥有哪些角色.可以说用户与角色之间的动态配置和判断security做的非常不错.不过在配 ...
- 1.python环境配置 - python基础入门
工欲善其事必先利其器,python学习首先要做得就是配置python环境.配置环境只需要下载Pycharm 和 Anaconda两个安装包即可,请跟上我得步伐,一步一步操作. 重要的事情说三遍: 先安 ...
- centos6.9实时查看tomcat运行日志
1.切换到tomcat的logs目录下 cd /usr/local/apache-tomcat-/logs 2.执行命令,查看日志 tail -f catalina.out 3.退出 Ctrl+c
- Python——Pandas速查手册中文版
转自——http://blog.csdn.net/qq_33399185/article/details/60872853,非常感谢大神的整理! 还有图片版,转自——https://zhuanlan. ...
- 从无到有,构建GIS + BIM大厦
声明:本文是一个系列原创(作者在GIS+BIM行业已有从业15年有余,还是个行业的小学生,文章内容不免有错误或者不当之处,敬请理解),旨在通过这个系列打造一个高性能,高可扩展的GIS+BIM框架,抛砖 ...
- Java 学习笔记之 线程安全
线程安全: 线程安全的方法一定是排队运行的. public class SyncObject { synchronized public void methodA() { try { System.o ...