2.6 C#语法的学习(六) && 异常处理 && 调试
程序在遇到问题无法继续执行时,会抛出异常
告知开发/用户。开发需要做的事情就是,在开发过程中,尽量减少异常发生的可能,同时完成异常捕获,保证丑陋的异常不会直面用户。
同时,异常内容也是调试过程中非常重要的讯息。
打断点调试
调试的目的是检验我们的代码是否有问题,代码是否按照我们的想法在正确的执行。
打断点调试则是最基本的调试方式。在调试过程中,配合Locals
、Immediate Window
、Watch
等窗口可以很方便的调试。
它可以使程序停在我们指定的位置上,让我们查看当前变量的情况、对数据进行修改、执行一些方法,拖动程序到我们想执行的代码段。
具体的内容可以看这里,这篇文章讲的很细很全。我们搜索的关键词应该是“Vs debug” 、“Vs 调试” 。
使用try-catch捕获异常
try-catch-finally
可以理解为“尝试做什么事………………如果出错就……………………最后收尾工作完成………………”。
尝试成功,则不执行“出错”代码段。尝试失败,就进入“出错”代码段。
无论失败成功,一定会执行“收尾工作”。并且收尾工作finally是可选的,根据情况写或者不写。
比较细节的是,“出错”的代码段可以有多个,因为出错的原因可以有很多个嘛~在catch(Exception ex)中,可以填写不同的Exception,C#就会根据实际捕获的Exception类型
进入对应的catch代码段,并且把异常对象赋值给ex
。
try-catch语句的详细教程点击这里。
try-catch的应用非常广泛:
1.调试的时候通过捕获异常+打断点的方式,查看异常详情。
2.通过catch捕获不同的异常,分情况执行不同的代码。
比如:读取数组并存储(来自C# try catch finally:异常处理)
//定义存放5个整数的数组
int[] a = new int[5];
try
{
for (int i = 0; i < a.Length; i++)
{
a[i] = int.Parse(Console.ReadLine());
}
for (int i = 0; i < a.Length; i++)
{
Console.Write(a[i] + " ");
}
}
catch (FormatException f)
{
Console.WriteLine("输入的数字格式不正确!");
}
catch (OverflowException o)
{
Console.WriteLine("输入的值已经超出 int 类型的最大值!");
}
catch (IndexOutOfRangeException r)
{
Console.WriteLine("数组越界异常!");
}
catch(Exception ex)
{
Console.WriteLine("哇哦,出错了!");
}
3.对于容易出问题的代码段,加上try-catch之后发布程序。在catch代码段中可以拦截异常,给用户友好的提示,并且记录日志,以便复现和分析问题。此方法特别适用于无法调试的情况。
延展:全局捕获异常
是不是感觉try-catch很好用?那我是不是该给我的所有代码加上try-catch,来保证它们不出错?我告诉你,你会被其他开发打死的!
这样代码会很丑、很丑,不能忍那种。再来,try-catch是要消耗性能的(具体搜索“C# try catch 性能”),你说你一个“var i=1;”这样的代码加什么try-catch?
那你说,我就是希望可以捕获到异常,让程序更健壮啊……我有错么?没有,但是我们可以用更好的方式来解决——————全局捕获异常。
当代码出错,并且这段代码没有在try-catch里面,则这个异常会被“全局捕获异常”所捕获。明白了么?try-catch是针对程序某一段代码的缝纫机,全局捕获异常是整个程序的缝纫机。try-catch没有处理到的异常,就会交给全局捕获异常来处理。全局捕获异常就像最后一道防火墙一样。
全局捕获异常在不同的开发框架下不尽相同,我也记不住~记住有这个神器,会搜索就行,比如“WPF 全局捕获异常”、“ASP .NET 全局捕获异常”、“Winfrom 全局捕获异常”,一搜一大把。
相同的,我们应该在全局捕获异常的地方认真记录出错原因,并且拦截异常,向用户显示友好的提示。
打日志
打日志的本质是在程序运行过程中,记录一些内容到文本文档、数据库等持续化存储的地方。我们的关键词是“C# 日志”、“.net 日志”。
打日志的目的也很多:
1.捕获异常并记录下详细信息(方法名、参数、报错位置等等),便于复现和解决问题。
2.因为业务需求,记录一些流水性内容,比如某用户在什么时候执行了什么操作调用了什么接口。
3.用于调试,特别是服务器上程序的调试。
......
C#日志比较出名的库一个是log4net,一个是NLog。都是在nuget可以找到并安装,可以直接使用的库。像这种第三方库,根据关键词“log4net” 、“NLog”找到官网,在官方“Get Start”或者“Quick Start”里面都可以快速入门。英语不好的同学也可以选择中文的博客来进行学习。
在这些完善好的日志系统中,日志的内容是分级的,一般分为Trace
、Debug
、Info
、Error
、Fatal
。开发者可以根据自己感兴趣的日志层级进行灵活设置。
延展:自行实现日志功能的姿势和可行性
当然你也可以选择自己实现日志记录。想想日志实际上是什么?最简单的就是文本文档记录一些内容。
“文本文档记录”,是不是“C# 创建txt文本”?老规矩,我们搜一搜:
是不是瞬间觉得简单了~所以,不要害怕,这些都是无数人踩过的坑。
创建txt之后,是不是就是“读”和“写”日志的问题了——————“C# 读写txt”,就可以找到答案(甚至上一个关键词“C# 创建txt文本”的部分搜索结果就已经有答案了)。
再来,数据库记录日志,是不是实际上就是“建立日志表-插入日志记录”,难么?不难,就是一些数据库的操作而已。
那既然这么简单,为什么大家会选用log4net、NLog这样第三方的库,而不是自己实现呢?
首先,开发者普遍认为“不要重复造轮子”
。在这个问题中,log4net、NLog就是别人造好的、可以直接使用的轮子,既然可以直接上路,为什么还要努力造自己的轮子?而且你造出来大概率还没有现有的轮子好看、好用,所以还是直接用吧!
再来,我刚刚说的实现日志,只是最简单的情况,实际上你去看log4net、NLog的源代码或者文档,你会发现“记录日志”这件事被他们弄得“很复杂”。
比如刚刚说的分级问题;比如不同时间的日志是放在一个文档里面还是分日期/分月/分小时放在不同的文档里面,文档多了是不是要分文件夹;比如一个文档的最大大小是否有限制,如果超过了这个限制应该怎么办,是新建一个文档继续记录还是覆盖当前文档前面的记录;怎么让这些需要配置的地方变得灵活;不同框架的支持甚至是不同IDE的支持(如果有,这个多适用于一些前端显示化框架)………………
你跟我说这些你自己写么?可以但没必要啊,直接用吧,感兴趣还可以看看人家代码是怎么写的,给他们提提意见(Issures),为项目添砖加瓦(Pull Request),多好。
最后,是代码维护成本的问题。像这些库都是有开发者在一直持续更新的,这保证了即使你的程序之后升版本、需要迁移,你只需要更新这些库,可能还会改点代码就可以继续使用它们了。即使改代码也不用担心,官网大概率会出迁移方面的说明文档,照做即可。而如果是自己写呢?你可能就需要重新写一套记录日志的代码了。
远程调试
有时候我们会遇到在开发机运行ok,发布到服务器就GG的问题。然后百思不得其解,然后崩溃o(≧口≦)o
这时候不要慌张,我们可以远程调试
。搜索关键词“C# 远程调试”、“VS 远程调试”都可以。
它可以让我们像在开发机上调试程序一样,调试服务器上的程序。
学习技术最好的文档就是【官方文档】,没有之一。
还有学习资料【Microsoft Learn】、【CSharp Learn】、【My Note】。
如果,你认为阅读这篇博客让你有些收获,不妨点击一下右下角的【推荐】按钮。
如果,你希望更容易地发现我的新博客,不妨点击一下【关注】。