C#学习 - 方法的定义、调用、调试

方法

  • 方法(Method)是由C/C++中的函数(Function)发展而来的
//C语言
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}//函数
int main(void)
{int a = 4;int b = 2;int c = Add(a, b);printf("%d + %d = %d\n", a, b, c);return 0;
}
//C++
#include <iostream>
int Add(int x, int y)
{return x + y;
}//函数
int main()
{int a = 4;int b = 2;int c = Add(a, b);std::cout << a << " + " << b << " = " << c;return 0;
}

方法是面向对象,当一个函数以类的成员出现的时候就叫方法,所以方法又叫成员函数
在编写C++程序时,选择添加类(Class),然后输入类名,后面的 .h 文件就是类的声明,而 .cpp 文件就是类的定义(在C#中类的声明和定义是放在一起的)C++程序添加类

//ABC.h - 类的声明
#pragma once
class ABC
{
public:void ShowHello();
};//ABC.cpp - 类的定义
#include "ABC.h"
#include <iostream>
void ABC::ShowHello()
{std::cout << "Hello World";
}//use.cpp
#include <iostream>
#include "ABC.h"
int main()
{ABC* pABC = new ABC();//此处已经有了C#方法的雏形了pABC->ShowHello();return 0;
}
  • 方法是类(或结构体)的成员

C#中函数不能独立于类(或结构体)之外
只有作为类(或结构体)的成员出现时,函数才能被称为方法

namespace ConsoleApp1
{int Add(int x, int y){return x + y;}internal class Program{static void Main(string[] args){ }}
}

上段代码中的函数没有在类中,编译会报错

  • 方法是类(或结构体)最基本的成员之一
    类(或结构体)有两个最基本的成员 - 字段和方法(成员变量和成员函数)
    方法表示类(或结构体)所能干的事情
  • 使用方法和函数的目的
    1. 隐藏复杂的逻辑;
    2. 把大算法分解为小算法;
    3. 复用;
//未复用
class Tool
{public double GetCicleArea(double R){return 3.14 * R * R;}public double GetCylinderVolume(double R, double H){return 3.14 * R * R * H;}public double GetConeVolume(double R, double H){return 3.14 * R * R * H / 3;}
}
//复用
class Tool
{public double GetCicleArea(double R){return 3.14 * R * R;}public double GetCylinderVolume(double R, double H){return GetCicleArea(R) * H;}public double GetConeVolume(double R, double H){return GetCyliderVolume(R, H) / 3;}
}

将一个大的算法分解为小的算法,再由算法一个一个解决,就是自顶向下逐步求精的方法

方法的声明与调用

方法的声明

函数头 + 函数体
函数头:特性 + 有效的方法的修饰符 + partial + 返回类型 + 方法名 + 类型参数列表 + ( + 形式参数列表 + )+ 类型参数约束句子
其中只有 返回类型 & 方法名 & **()**是必须要的;其中 类型参数约束句子 只有在有 类型参数列表 出现时才能出现
方法名最好使用动词或动词短语,所有单词首字母大写(Pascal命名法)
形式参数(parameter,简称:形参):是一种变量,会参与构成方法的算法逻辑

静态方法和实例方法

静态方法与类绑定,非静态方法(实例方法)与实例绑定

using System;namespace ConsoleApp1
{internal class Program{static void Main(string[] args){Tool t = new Tool();Console.WriteLine(t.Add(1, 2));//实例方法与实例绑定Console.WriteLine(Tool.Sub(1,2));//静态方法与类绑定}}class Tool{public int Add(int x, int y){ 	//实例方法return x + y;}public static int Sub(int x, int y){	//静态方法return x - y;}}
}

调用方法

方法调用:方法名 + ( + 实际参数列表 + )
实际参数(Argument,简称:实参):实际参数列表需要与定义方法时的形式参数列表相匹配
以上面那段代码为例:

int x = Tool.Sub(1);
//此时实际参数个数与形式参数不匹配
int y = Tool.Sub(1.0, 2.5);
//此时实际参数类型与形式参数不匹配

构造器

构造器(Constructor)是类型的成员之一,构造器就是构造函数
狭义的构造器就是实例构造器(Instance constructor)

using System;namespace ConsoleApp1
{internal class Program{static void Main(string[] args){Human human = new Human();//上行代码中的 () 就是调用构造器Console.WriteLine(human.ID);Console.WriteLine(human.Name);People people = new People();Console.WriteLine(people.ID);Console.WriteLine(people.Name);Student student = new Student(1, "None");//构造器带参数时调用也需要带参数Console.WriteLine(student.ID);Console.WriteLine(student.Name);}}class Human{ //当声明一个类后,没有准备构造器时,编译器会自动为其准备一个默认构造器//默认构造器可以把内存中的对象的字段进行初始化,就是将 ID 和 Name 进行初始化public int ID;public string Name;}class People{public People(){   //创建构造器时,构造函数名要与类一致this.ID = 0;this.Name = "NULL";}public int ID;public string Name;}class Student{public Student(int id, string name){this.ID = id;this.Name = name;}public int ID;public string Name;}
}

一个类中可以有多个构造器

class People
{public People(int id, string name){this.ID = id;this.Name = name;}public People(){this.ID = 0;this.Name = "NULL";}public int ID;public string Name;
}

构造器的内存原理

默认构造器

Human human = new Human();
class Human
{public int ID;public string Name;
}

第一个代码创建了一个human变量,human变量存储在栈区中(栈区存储由高字节位到低字节位)
new操作符开始执行时,在堆区找足够的内存空间作为实例的内存,而 int 需要占4字节,string 需要占4字节,所以最后占用了8个字节。构造时就对这8个字节进行切割,前4个为int类型,后4个为string类型,然后默认构造器将这8个字节中的值全赋值为0
最后将实例的地址存储在human变量中

带参数的构造器

Human human = new Human(1, "One");
class Human
{public Human(int id, string name){this.ID = id;this.Name = name;}public int ID;public string Name;
}

依旧是在栈区分配human变量的内存空间,然后在堆区分配8字节,然后开始切割这8个字节,再在前4个字节中存入1,在后4个字节中存入“One”
最后把实例的地址放进human变量的内存空间中

方法的重载(Overload)

当一个类中的两个方法的名称一致时,方法签名不能一致
方法签名(Method signature)由方法名称、类型形参的个数和方法的形参(由左到右的顺序)的类型、种类(值、引用、输出)组成,方法签名不包含返回类型

class Tool
{public int Add(int a, int b){ return a + b; }public double Add(double a, double b){ return a + b; }public int Add(int a, int b, int c){ return a + b + c; }public int Add(ref int a, out int b){ b = 10; return a + b; }//ref就是引用、out就是输出
}

构造器也可以有重载,构造器的签名由每一个形参(从左到右的顺序)的类型和种类(值、引用、输出)组成
重载决策:根据调用方法时实参的类型来决定调用哪一个方法。如:

Console.WriteLine(100);
Console.WriteLine("Hello World");

对方法进行debug

debug可以找到bug发生的地方,也可以了解到程序运行的原理

设置断点(breakpoint)

设置断点后,运行程序时会自动停在断点设置处断点
红色就是断点标识,设置快捷键是F9,然后按F5进行调试,就会执行时停到断点处调试后
当红点标识变成上图标识时,就是程序执行停在了那里

观察方法调用时的调用堆栈(call stack)

Call stack
上图中第一行就是断点处的方法(函数)
第二行就是调用它的函数,可以双击跳到所需位置
实际代码中此处可能会层层叠加,最后一行就是最外层调用,而红点标识处就是断点处

逐语句(Step-into)、逐过程(Step-over)、跳出(Step-out)

Step-into(F11)会进入所调用的方法中去
Step-over(F10)不会进入所调用的方法中,没有Step-into细致
Step-out(Shift+F11)可以从一个方法中直接回到调用它的那段代码上

观察局部变量的值与变化

在监视中观察监视
将鼠标移到变量处,可以标识出变量的值,当语句调试到那一处时,会自动将被标识的变量的值显示出来

方法调用时栈内存的分配

stack frame:一个方法被调用时,它在栈内存当中的布局
当代码执行到一个方法时,在栈区中分配一个内存
当在A方法中调用一个B方法时用到了实际参数,传的参数也会分配到栈区中,在C#中这些实际参数归A方法管
分配参数内存时,在C#中先分配左边的参数,再分配右边的参数
当一个方法调用结束后,会回收给它分配的内存,且传递的实参所占的内存也会被回收
方法的返回值会存在cpu的寄存器(一种高速内存)中,当寄存器空间不够存放返回值时才会存放在栈区

using System;namespace ConsoleApp1
{internal class Program{static void Main(string[] args){Tool tool = new Tool();Console.WriteLine(tool.Add(1, 2));}}class Tool{public int Add(int a, int b){int c = Sub(a, b);return c;}public int Sub(int a, int b){int c = a - b;return c;}}
}

栈区内存分配
上图就是上段代码执行到方法Sub时的栈区内存分配,继续执行就会从上往下慢慢回收已经调用结束的方法所占的内存
注:上图只标识了参数内存分配,实际上还有其他很多元素会分配到栈区中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/129916.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识MyBatis(一)基于配置文件下的一些增删改查

MyBatis可以使用简单的XML或注解用于配置和原始映射&#xff0c;将接口和Java的POJO&#xff08;Plain Old Java Objects&#xff0c;普通的Java对象&#xff09;映射成数据库中的记录 MyBatis 是一个 半自动的ORM&#xff08;Object Relation Mapping&#xff09;框架 创建好m…

《计算机网络安全》DNS与它的具体作用解析

初步了解DNS 个人介绍DNS定义DNS作用DNS的生活加速作用科普 个人介绍 &#x1f338;一名大四备考考研学子&#xff0c;喜欢前端&#xff0c;还有Android和JAVA开发 &#x1f332;爱看书和打游戏还有唱歌 &#x1f352;热爱编程和读古今中外名著 &#x1f33a;座右铭&#xff1…

el-form表单中不同数据类型对应的时间格式化和校验规则

1. 在表单中, 当选择不同的数据类型时, 需要在下面选择时间时和数据类型对应上, 通过监听数据类型的变化, 给时间做格式化, 2. 但是当不按顺序选择数据类型后, 再选时间可能会报错, 所以需要在dom更新后, 再清空表单. 3. 校验规则, 结束时间需要大于开始时间, 但是不能选当前的…

Jmeter引入外部jar包以满足加密数据的Post请求

目录 一、把项目打成jar包 1、创建一个Maven项目&#xff0c;并保证可以正常运行。 2、把工具类放置项目中&#xff0c;确保无报错且能够正常使用。 3、打包 4、验证 jar包是否有效 5、你想打多个工具类的包 二、在jmeter中使用 1、把jar包放到jmeter仓库下&#xff0c;…

Mixin从理论到实践

mixin从理论到实践 mixin从理论到实践一、什么是mixin二、使用mixin三、mixin的合并策略四、mixin辨析五、个人实践 mixin从理论到实践 一、什么是mixin mixin混入 — Vue.js (vuejs.org) 官方解释&#xff1a; 混入 (mixin) 提供了一种非常灵活的方式&#xff0c;来分发 Vue …

安全生产:CVE-2020-11022/CVE-2020-11023漏洞解析

文章目录 一、前言二、漏洞原理三、修复方案3.1 升级jQuery3.2 1.x 升级至 3.x 需要考虑的问题3.2.1 table表格元素自动添加tbody3.2.2 方法变更 3.3 jquery migrate是什么 四、拓展阅读 一、前言 代码安全扫描阶段&#xff0c;前端资源审计发现jQuery版本过低导致生产系统存在…

96. 不同的二叉搜索树

class Solution { public:int numTrees(int n) {if (n0) {return 1;}vector<int> dp(n1, 0);dp[0] 1;dp[1] 0;for (int i 1; i < n; i) {for (int j 0; j < i; j) {dp[i] dp[j] * dp[i - 1 - j];}}return dp[n];} };

grpc多语言通信之GO和DART

都是一个吗生的,找下例子 上一篇文章说到go实现的grpc方法已经实现了一个grpc的server端, 注意: 这两个项目的.proto文件应当是完全一致的,只是方法用各自的语言实现罢了 报错了: Caught error: gRPC Error (code: 12, codeName: UNIMPLEMENTED, message: grpc: Decompresso…

网络传输方式

1. 单播 1.1. 定义 单播是指一种向单个目标地址传送数据的方式&#xff0c;即单独的一对一通讯方式。 1.2. 可使用协议 UDP、TCP等协议 1.3. 常见的场景 发送电子邮件传输文件 2. 广播 2.1. 定义 一种向本地网络中所有设备发送数据的方式。 2.2. 常见的场景 电视和电…

SpringBoot+Vue 整合websocket实现简单聊天窗口

效果图 1 输入临时名字充当账号使用 2 进入聊天窗口 3 发送消息 &#xff08;复制一个页面&#xff0c;输入其他名字&#xff0c;方便展示效果&#xff09; 4 其他窗口效果 代码实现 后端SpringBoot项目&#xff0c;自行创建 pom依赖 <dependency><groupId…

有效回文字符串(Valid palindrome)

题目描述 思路分析 代码实践 java: public class Solutation1 {//定义一个方法&#xff0c;判断是否是有效数字或者字母private static boolean isValid(char c) {//如果不是字母或者数字&#xff0c;那就返回一个flase//这里调用了Character类里面的方法return Character.i…

Python - PyQt6、QDesigner、pyuic5-tool 安装使用

Python 开发可视化界面可以使用原生的 tkinter&#xff0c;但是原生框架使用起来颇为不方便&#xff0c;所以最流行的还是QT UI框架&#xff0c;QT是使用C语言开发&#xff0c;Python 想使用需要对其进行封装&#xff0c;所以就出现了PyQt框架&#xff0c;这个框架使用极其方便…

element的el-select给下拉框添加背景

第一步 :popper-append-to-body"false" <el-selectv-model"value"placeholder"请选择":popper-append-to-body"false"><el-optionv-for"item in options":key"item.value":label"item.label&quo…

【算法专题突破】双指针 - 最大连续1的个数 III(11)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;1004. 最大连续1的个数 III - 力扣&#xff08;Leetcode&#xff09; 这道题不难理解&#xff0c;其实就是求出最长的连续是1的子数组&#xff0c; 但是&#xff0c;他支…

Spring Reactive:响应式编程与WebFlux的深度探索

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

2023-简单点-什么是protobuf?

protobuf mother: 谷歌 作用 序列化 人话&#xff1a; 存储数据的一种结构 优势在&#xff1f; 类型安全 易用性好 序列化/反序列性能好 兼容性好 不仅可以定义结构体&#xff0c;还可以定义rpc服务接口 劣势在&#xff1f; 可读性较差&#xff1a;没有schema的情况下&a…

Linux--进程--进程-父进程退出

1.进程退出函数 进程退出分为正常退出&异常退出 正常退出&#xff1a; 1、main函数调用return 2、进程调用exit(),标准c库 3、进程调用_exit()或者_Exit(),属于系统调用 补充 1、进程最后一个线程返回 2、最后一个线程调用pthread_exit 异常退出&#xff1a; 1、调用abo…

【开箱即用】开发了一个基于环信IM聊天室的Vue3插件,从而快速实现仿直播间聊天窗功能

前言 由于看到有部分的需求为在页面层&#xff0c;快速的引入一个包&#xff0c;并且以简单的配置&#xff0c;就可以快速实现一个聊天窗口&#xff0c;因此尝试以 Vue3 插件的形式开发一个轻量的聊天窗口。 这次简单分享一下此插件的实现思路&#xff0c;以及实现过程&#xf…

OpenCV(二十二):均值滤波、方框滤波和高斯滤波

目录 1.均值滤波 2.方框滤波 3.高斯滤波 1.均值滤波 OpenCV中的均值滤波&#xff08;Mean Filter&#xff09;是一种简单的滤波技术&#xff0c;用于平滑图像并减少噪声。它的原理非常简单&#xff1a;对于每个像素&#xff0c;将其与其周围邻域内像素的平均值作为新的像素值…

5.9.Webrtc线程事件处理

在前面的课程中呢&#xff0c;我已经向你介绍了事件处理的一些基础知识&#xff0c;那今天呢&#xff0c;我们再来看一下外边儿rtc下事件处理的基本逻辑是什么&#xff1f; 那首先呢&#xff0c;我们来看一下事件是如何协调线程工作的&#xff0c;那就如果这张图所展示的有两个…