C#中级教程(1)——解锁 C# 编程的调试与错误处理秘籍

news2025/5/14 2:44:52

一、认识错误:编程路上的 “绊脚石”

        在 C# 编程中,错误大致可分为两类:语法错误语义错误(逻辑错误)语法错误就像是写作文时的错别字和病句,编译器一眼就能识别出来,比如变量名拼写错误、符号使用不当等,这类错误会导致程序无法正常编译。而语义错误则像是作文的内容逻辑不通顺,代码虽然能正常编译通过,但运行结果却和预期大相径庭,这往往是因为程序的逻辑在某些方面存在瑕疵。

// 错误示例:变量声明时未指定类型
undeclaredVariable = 10; 
// 语义错误示例:判断逻辑错误,原本想判断是否大于5,却写成了小于
int num = 7;
if (num < 5) 
{
    Console.WriteLine("数字大于5");
}

二、调试技巧:寻找错误的 “放大镜”

(一)正常模式下的调试 “小妙招”

        在正常模式下,借助输出语句来查看变量的值是一种简单有效的调试方法。在使用 Visual Studio(VS)进行 C# 开发时,Console.WriteConsole.WriteLine是我们的得力助手。例如,在一个计算两个数之和的程序中:

int num1 = 5;
int num2 = 10;
int sum = num1 + num2;
Console.WriteLine("num1的值为:" + num1);
Console.WriteLine("num2的值为:" + num2);
Console.WriteLine("两数之和sum的值为:" + sum);

        通过这些输出语句,我们可以清晰地看到每个变量在程序执行过程中的具体值,以此判断程序的运行是否符合预期。如果sum的值不是 15,那就说明代码中可能存在问题,需要进一步排查。

        在 Unity 开发环境中,Debug.LogDebug.LogErrorDebug.LogWarn则发挥着类似的作用。假设我们正在开发一款游戏,角色的移动速度出现了异常,我们可以在相关代码中添加Debug.Log语句:

public class PlayerMovement : MonoBehaviour
{
    public float speed = 5f;
    void Update()
    {
        Debug.Log("当前角色的移动速度为:" + speed);
        // 角色移动相关代码
    }
}

        这样,在 Unity 的 Console 窗口中,我们就能实时查看角色移动速度的变化情况,从而找出速度异常的原因。


(二)中断模式:深入代码内部的 “显微镜”

1.断点:程序的 “暂停按钮”
        断点是进入中断模式的关键。在 VS 中,设置断点的方法多种多样。你可以右键单击代码行,选择 “breakpoint” -> “insert breakpoint”;也可以将光标定位到代码行,通过菜单上的 “Debug” -> “Toggle Breakpoint” 来设置;更为便捷的是,直接按下 F9 键就能快速设置或取消断点;另外,在需要添加断点的行首位置直接单击,同样可以实现断点的添加与取消

        例如,在下面这段代码中:

int result = 0;
for (int i = 1; i <= 10; i++)
{
    result += i;
}
Console.WriteLine("1到10的累加和为:" + result);

        我们在result += i;这一行设置断点,当程序运行到这一行时,就会自动暂停,进入中断模式。


2.调试窗口:代码状态的 “监控中心”
        进入中断模式后,VS 提供了多个实用的调试窗口,帮助我们深入了解程序的运行状态。
  • 断点窗口:通过 “调试 - 窗口 - 断点” 打开,这里展示了当前项目中所有的断点信息。我们可以在这个窗口中快速定位断点位置,还能方便地删除不再需要的断点。

  • 变量查看窗口:把鼠标指向源代码中的变量名,就能通过工具提示查看变量的信息。此外,在中断模式下的左下角,有 “错误列表”“局部变量”“监视” 三个选项卡。“错误列表” 展示了程序运行中发生的所有错误;“局部变量” 显示当前运行环境中所有局部变量的值;“监视” 则用于跟踪某个特定变量的值的变化。不仅如此,在这些窗口中,我们还能直接修改变量的值,这对于调试复杂的逻辑错误非常有帮助。
  • 调用堆栈和即时窗口:在中断模式的右下角,“调用堆栈” 窗口能让我们清晰地看到当前代码执行到哪一行,以及是被什么语句调用的,这对于理清程序的执行流程至关重要。“即时窗口” 则像是一个小型的代码执行控制台,我们可以在这里输入命令,查看变量的值、修改变量的值,还能输入表达式查看计算结果。例如,在即时窗口中输入result,就能查看当前result变量的值;输入result = 100,可以修改result的值。


3.单步执行:代码执行的 “慢动作”


        单步执行是调试过程中的重要操作,它分为 “逐过程” 和 “逐语句” 两种方式。两者都是逐行执行代码,但 “逐过程” 在遇到函数时,不会进入函数内部,而是把函数当成一条语句直接执行“逐语句” 则会深入函数内部,逐行执行函数中的代码。例如,在下面的代码中:

int num1 = 3;
int num2 = 5;
int sum = AddNumbers(num1, num2);
Console.WriteLine("两数之和为:" + sum);

static int AddNumbers(int a, int b)
{
    return a + b;
}

        如果使用 “逐过程” 执行,当执行到int sum = AddNumbers(num1, num2);时,会直接执行完AddNumbers函数并返回结果;而使用 “逐语句” 执行,则会进入AddNumbers函数内部,逐行执行return a + b;这一行代码。


三、错误处理:程序的 “保护盾”

(一)异常:运行时的 “潜伏危机”

        异常是程序在运行期间产生的错误。例如,当我们访问数组中不存在的元素时,就会引发异常。看下面这个例子:

int[] numbers = { 1, 2, 3 };
try
{
    int value = numbers[3];
}
catch (IndexOutOfRangeException e)
{
    Console.WriteLine("发生数组下标越界异常:" + e.Message);
}

        在这个例子中,数组numbers的有效下标范围是 0 到 2,当尝试访问numbers[3]时,就会抛出IndexOutOfRangeException异常。如果不处理这个异常,程序就会终止,后续的代码将无法执行。


(二)异常处理:构建程序的 “防护网”

        C# 中处理异常的语法结构主要由trycatchfinally三个关键字组成。

  • try 块:包含可能会出现异常的代码。例如,在读取用户输入并转换为整数的操作中,可能会因为用户输入非数字字符而引发异常,这部分代码就可以放在try块中:
try
{
    Console.Write("请输入一个整数:");
    int number = int.Parse(Console.ReadLine());
    Console.WriteLine("你输入的整数是:" + number);
}
  • catch 块:用于捕捉并处理异常。当try块中的代码发生异常时,如果异常的类型和catch块中指定的类型匹配,就会执行该catch块中的代码catch块可以有多个,用于处理不同类型的异常。例如:
catch (FormatException e)
{
    Console.WriteLine("输入的内容格式不正确,请输入一个有效的整数。异常信息:" + e.Message);
}
catch (OverflowException e)
{
    Console.WriteLine("输入的数字超出了范围。异常信息:" + e.Message);
}

        如果catch块中不指定异常类型,即catch()那么它将捕捉所有类型的异常,但这种方式在实际开发中要谨慎使用,因为它可能会掩盖一些具体的异常信息,不利于问题的排查。

  • finally 块:无论try块中是否发生异常,finally块中的代码都会执行。这在一些需要释放资源的场景中非常有用,比如关闭文件流、数据库连接等。例如:
finally
{
    Console.WriteLine("这是finally块,无论是否发生异常,我都会被执行。");
}

(三)实际案例:用户输入处理

        接下来,我们通过一个完整的案例来展示异常处理的实际应用。要求用户输入两个数字,计算它们的商,并处理可能出现的异常,如用户输入非数字字符、除数为零等情况。

while (true)
{
    try
    {
        Console.Write("请输入第一个数字:");
        double num1 = double.Parse(Console.ReadLine());

        Console.Write("请输入第二个数字:");
        double num2 = double.Parse(Console.ReadLine());

        if (num2 == 0)
        {
            throw new DivideByZeroException("除数不能为零");
        }

        double result = num1 / num2;
        Console.WriteLine("两数相除的结果是:" + result);
        break;
    }
    catch (FormatException e)
    {
        Console.WriteLine("输入的内容格式不正确,请输入有效的数字。异常信息:" + e.Message);
    }
    catch (DivideByZeroException e)
    {
        Console.WriteLine(e.Message);
    }
    catch (Exception e)
    {
        Console.WriteLine("发生了其他异常:" + e.Message);
    }
}

        在这个案例中,使用while (true)循环确保用户在输入有误时能够重新输入。try块中包含了获取用户输入、转换为数字以及计算除法的代码。通过多个catch块分别处理不同类型的异常,最后使用finally块来执行一些无论是否发生异常都需要执行的操作(在这个案例中没有添加特定的finally代码,但在实际应用中可以根据需求添加)。


四、总结

        调试和错误处理是 C# 编程中至关重要的技能,它们就像编程道路上的 “护航员”,帮助我们及时发现并解决代码中的问题,确保程序的稳定运行。通过合理运用各种调试技巧和正确处理异常,我们能够编写出更加健壮、可靠的程序。希望大家在今后的编程实践中,不断积累经验,熟练掌握这些技能,让编程之路更加顺畅。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter接口并发测试

Apache JMeter 是一款开源的性能测试工具&#xff0c;广泛用于接口并发测试、负载测试和压力测试。以下是使用 JMeter 进行接口并发测试的详细步骤&#xff1a; 一、准备工作 安装 JMeter 下载地址&#xff1a;Apache JMeter 官网 确保已安装 Java 环境&#xff08;JMeter 依…

MySQL-增删改查

一、Create(创建) &#x1f4d6; 语法&#xff1a; INSERT INTO table_name(value_list); 当我们使用表的时候&#xff0c;就可以使用这个语法来向表中插入元素~ 我们这边创建一个用于示范的表(Student)~ create table student( id int, name varchar(20), chinese int, math…

开源堡垒机 JumpServer 社区版实战教程:发布机的配置与Website资产配置使用

文章目录 开源堡垒机 JumpServer 社区版实战教程&#xff1a;发布机的配置与Website资产配置使用一、功能简述二、应用发布机2.1 版本要求2.2 创建应用发布机2.2.1 通过WinRM的协议进行应用发布机的创建2.2.2 通过OpenSSH的协议进行应用发布机的创建2.2.2.1 下载OpenSSH2.2.2.2…

代码随想录算法训练day64---图论系列8《拓扑排序dijkstra(朴素版)》

代码随想录算法训练 —day64 文章目录 代码随想录算法训练前言一、53. 117. 软件构建—拓扑排序二、47. 参加科学大会---dijkstra&#xff08;朴素版&#xff09;总结 前言 今天是算法营的第64天&#xff0c;希望自己能够坚持下来&#xff01; 今天继续图论part&#xff01;今…

2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷(四)

2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷&#xff08;四&#xff09; 第一部分&#xff1a;网络平台搭建与设备安全防护任务书第二部分&#xff1a;网络安全事件响应、数字取证调查、应用程序安全任务书任务 1&#xff1a;应急响应&…

单片机的串口(USART)

Tx - 数据的发送引脚&#xff0c;Rx - 数据的接受引脚。 串口的数据帧格式 空闲状态高电平&#xff0c;起始位低电平&#xff0c;数据位有8位校验位&#xff0c;9位校验位&#xff0c;停止位是高电平保持一位或者半位&#xff0c;又或者两位的状态。 8位无校验位传输一个字节…

动态规划(背包问题)--是否逆序使用的问题--二进制拆分的问题

动态规划&#xff08;背包问题&#xff09; 题目链接01背包代码 完全背包问题代码 多重背包问题 I代码 什么时候适用逆序多重背包问题 II&#xff08;超百万级的复杂度&#xff09;代码 关于二进制拆分 题目链接 01背包 代码 #include <iostream> #include <vector&…

Mac 版 本地部署deepseek ➕ RAGflow 知识库搭建流程分享(附问题解决方法)

安装&#xff1a; 1、首先按照此视频的流程一步一步进行安装&#xff1a;(macos版&#xff09;ragflowdeepseek 私域知识库搭建流程分享_哔哩哔哩_bilibili 2、RAGflow 官网文档指南&#xff1a;https://ragflow.io 3、RAGflow 下载地址&#xff1a;https://github.com/infi…

姿态矩阵/旋转矩阵/反对称阵

物理意义&#xff0c;端点矢量角速率叉乘本身向量&#xff1b; 负号是动系b看固定系i是相反的&#xff1b; 一个固定 在惯性导航解算中&#xff0c;旋转矢量的叉乘用于描述姿态矩阵的微分方程。你提到的公式中&#xff0c; ω i b b \boldsymbol{\omega}_{ib}^b \times ωibb…

【大语言模型】【整合版】DeepSeek 模型提示词学习笔记(散装的可以看我之前的学习笔记,这里只是归纳与总结了一下思路,内容和之前发的差不多)

以下是个人笔记的正文内容: 原文在FlowUs知识库上&#xff0c;如下截图。里面内容和这里一样&#xff0c;知识排版好看一点 一、什么是 DeepSeek 1. DeepSeek 简介 DeepSeek 是一家专注于通用人工智能&#xff08;AGI&#xff09;的中国科技公司&#xff0c;主攻大模型研发与…

ollama无法通过IP:11434访问

目录 1.介绍 2.直接在ollama的当前命令窗口中修改&#xff08;法1&#xff09; 3.更改ollama配置文件&#xff08;法2&#xff09; 3.1更新配置 3.2重启服务 1.介绍 ollama下载后默认情况下都是直接在本地的11434端口中运行&#xff0c;绑定到127.0.0.1(localhost)&#x…

Bugku CTF CRYPTO

Bugku CTF CRYPTO 文章目录 Bugku CTF CRYPTO聪明的小羊ok[-<>]散乱的密文.!? 聪明的小羊 描 述: 一只小羊翻过了2个栅栏 fa{fe13f590lg6d46d0d0} 分 析&#xff1a;栅栏密码&#xff0c;分2栏&#xff0c;一个栏里有11个 ①手动解密 f a { f e 1 3 f 5 9 0 l g 6 d 4 …

【洛谷】【ARC100E】Or Plus Max(高维前缀和)

传送门&#xff1a;Or Plus Max 高维前缀和 题目描述 長さ 2N の整数列 A0​, A1​, ..., A2N−1​ があります。&#xff08;添字が 0 から始まることに注意&#xff09; 1 ≤ K ≤ 2N−1 を満たすすべての整数 K について、次の問題を解いてください。 i,j を整数と…

SmolLM2:多阶段训练策略优化和高质量数据集,小型语言模型同样可以实现卓越的性能表现

SmolLM2 采用创新的四阶段训练策略&#xff0c;在仅使用 1.7B 参数的情况下&#xff0c;成功挑战了大型语言模型的性能边界&#xff1a; 在 MMLU-Pro 等测试中超越 Qwen2.5-1.5B 近 6 个百分点数学推理能力&#xff08;GSM8K、MATH&#xff09;优于 Llama3.2-1B在代码生成和文…

《Effective Objective-C》阅读笔记(中)

目录 接口与API设计 用前缀避免命名空间冲突 提供“全能初始化方法” 实现description方法 尽量使用不可变对象 使用清晰而协调的命名方式 方法命名 ​编辑类与协议命名 为私有方法名加前缀 理解OC错误模型 理解NSCopying协议 协议与分类 通过委托与数据源协议进行…

Hbase客户端API——语句大全

目录 创建表&#xff1a; 插入数据&#xff1a; 删除数据&#xff1a; 修改数据&#xff1a; 查询数据&#xff1a;Get 查询数据&#xff1a;Scan 查询数据&#xff1a;过滤查询 创建表&#xff1a; 检验&#xff1a; 插入数据&#xff1a; 验证 一次多条数据插入 验证&…

MQ(Message Queue)

目录 MQ(Message Queue)基本概念 为什么要使用消息队列&#xff1f; 使用消息队列有什么缺点&#xff1f; 如何保证消息不丢失?(如何保证消息的可靠性传输?/如何处理消息丢失的问题?) 通用的MQ场景&#xff1a; RabbitMQ如何保证消息不丢失&#xff1f; 生产者丢数据…

计算机网络————(三)

前文二 前文一 Websocket协议 是一种存在TCP协议之上的协议 当客户端需要了解服务器是否更新就需要不断给客户端发送请求询问是否更新&#xff0c;这行会造成服务端压力很大 而Websocket相当于服务器一旦更新了就会给客户端发送消息表明自己更新了&#xff0c;类似客户端订阅…

【音视频】音视频录制、播放原理

一、音视频录制原理 通常&#xff0c;音视频录制的步骤如下图所示&#xff1a; 我们分别从音频和视频开始采样&#xff0c;通过麦克风和摄像头来接受我们的音频信息和图像信息&#xff0c;这通常是同时进行的&#xff0c;不过&#xff0c;通常视频的采集会比音频的采集慢&…

deepseek 导出导入模型(docker)

前言 实现导出导入deepseek 模型。deepseek 安装docker下参考 docker 导出模型 实际生产环境建议使用docker-compose.yml进行布局&#xff0c;然后持久化ollama模型数据到本地参考 echo "start ollama" docker start ollama#压缩容器内文件夹&#xff0c;然后拷贝…