程序异常问题
为什么要进行异常处理
程序因为各种原因出现问题导致的结果是程序直接崩溃,结果和开发过程出现的问题结果大不一样。因此需要使用异常的处理来防止软件系统崩溃
程序中的安全隐患
-
网络故障导致数据库连接问题
-
用户的非法操作(数据验证失败)
-
数据处理中的任何意外(例如:查询超时,资源文件丢失等)
-
……
了解异常类Exception
.NET Framework中的异常的设计结构
常见的异常类
与参数有关的异常
此类异常类均派生自SystemException,用于方法成员传递参数时发生的异常
-
ArgumentException:用于处理参数无效的异常
-
FormatException:用于处理参数格式错误的异常
与数组有关的异常
此类异常类均派生自SystemException
-
IndexOutOfRangeException:用于处理索引超出数组长度所引发的异常
-
ArrayTypeMismatchException:用于处理数组中存储数据类型不正确的元素所引发的异常
与IO有关的异常
-
IOException:用于处理进行文件输入输出操作时所引发的异常
与内存溢出有关的异常
OverFlowException:用于处理程序逻辑错误造成的死循环异常
与算术有关的异常
ArithmeticException:用于处理与算术有关的异常,比如0作为除数
与数据库操作有关的异常
-
DbException:用于处理所有数据源操作异常类的基类
-
SqlException:用于处理针对SQL数据源的异常,比如数据库连接错误
处理异常的常用方法
异常处理的形式
-
即时处理:发现异常后随时处理并恢复程序
-
抛出异常:捕获异常后,重新封装异常信息或直接抛给调用者
编写异常处理的原则
在任何可能会发生异常的地方进行添加异常处理的方法
异常对象提供的重要信息
属性名称 | 说明 |
---|---|
Source | 此属性表示导致异常发生的应用程序或对象的名称 |
Message | 提供引发异常的详细描述信息 |
StackTrace | 提供在堆栈上所调用方法的详细信息,并首先显示最近调用的方法 |
使用Try-catch捕获和处理
-
Try中放可能会出现异常的代码
-
catch中表示如果try中的代码出现了异常则会直接进入到catch中执行
-
无论是否try中的代码会不会发生异常,最终都会执行finally中的代码
-
finally不是必须的模块
异常传递与自定义方法
异常处理和日常工作一样
-
“底层方法”将第一次捕获的异常传递给上级调用者进一步详细处理
-
“中层调用者”可以用多路捕获异常并封装详细异常信息
-
“顶层调用者”即在用户界面中继续处理异常
相当于:
顶层调用者是客户-出现异常只需要告诉客户可能操作未成功的人性化原因描述
中层调用者-程序的开发人员,在开发程序时对于可能发生的异常进行初步处理
底层方法-维护人员,将异常的详细信息汇报,并进行异常处理
模块封装和程序集
程序设计
使用面向对象逻辑实现的计算器
class Calcuator
{
public int Add(int i, int j)
{
return i + j;
}
public int Mul(int i, int j)
{
return i - j;
}
public int Max(int i, int j)
{
return i * j;
}
public int Div(int i, int j)
{
return i / j;
}
}
private void button1_Click(object sender, EventArgs e)
{
int num1 = int.Parse(textBox1.Text);
int num2 = int.Parse(textBox2.Text);
string type = comboBox1.SelectedItem.ToString();
Calcuator calc = new Calcuator();
if (type=="+")
{
label2.Text =calc.Add(num1, num2).ToString();
}
else if (type=="-")
{
label2.Text = calc.Mul(num1, num2).ToString();
}
}
新问题的引出
首先刚才是这款软件的第一个版本能够实现整数的基础运算。这个软件上线之后很多客户都在正常使用。
但是很多用户提出来了一些问题:
-
除法运算无法求出小数部分
-
运算的功能较少能否再添加一些功能
-
上个计算器类是由程序员A编写的,现在解决问题只能由程序员B来维护
关键问题:上个计算器类是由程序员A编写的,现在由程序员B来维护除过Calculator类以外的所有程序,客户的要求要更改但是程序员B不知道A编写的源码,如果计算器类需要变动只能由A来完成,与B无关,假如你是程序员A为了解决这个隐患如何做。
问题点:两个人写的代码在同一个项目中,无法满足客户要求
导致最终问题:这个程序假如更改完成,面临的是要将之前的第一个版本先下线,然后将新的程序第二个版本再上线,用户会有很多烦恼:计算机上出现了1.0、 1.1、1.2、1.3、....等一系列版本,
如何解决上述一系列问题
使用模块封装
-
右键解决方案>>选择“新建项目”>>(.NET Framework)类库
-
向类库中添加Calc类,并编写方法
public class Calc { /// <summary> /// 加法运算 /// </summary> /// <param name="i">参数1</param> /// <param name="j">参数2</param> /// <returns></returns> public int Add(int i, int j) { return i + j; } /// <summary> /// 减法运算 /// </summary> /// <param name="i">参数1</param> /// <param name="j">参数2</param> /// <returns></returns> public int Mul(int i, int j) { return i - j; } /// <summary> /// 乘法运算 /// </summary> /// <param name="i">参数1</param> /// <param name="j">参数2</param> /// <returns></returns> public int Max(int i, int j) { return i * j; } /// <summary> /// 除 /// </summary> /// <param name="i"></param> /// <param name="j"></param> /// <returns></returns> public double Div(int i, int j) { return Convert.ToDouble(i) /Convert.ToDouble(j); } }
-
右键选择生成类库项目,并打开类库程序文件夹Debug找到对应的类库.dll文件,这个dll(Dynamic Link Library)动态来接库文件,里面包含了这个类库中我们添加的所有的类,类中的所有方法,以对其内部C#代码编译后的结果进行保存(dll是一个.NET平台上能够直接执行的机器语言集合)
-
在主项目中添加对Calculator.dll文件的引用
-
在项目中使用Calculator类库中的Calc对象
Calc calc = new Calc(); private void button1_Click(object sender, EventArgs e) { int num1 = int.Parse(textBox1.Text); int num2 = int.Parse(textBox2.Text); string type = comboBox1.SelectedItem.ToString(); if (type=="+") { label2.Text = calc.Add(num1,num2).ToString(); } else if (type=="-") { label2.Text =calc.Mul(num1,num2).ToString(); } else if (type=="×") { label2.Text =calc.Max(num1,num2).ToString(); } else if (type=="÷") { label2.Text = calc.Div(num1, num2).ToString() ; } }
模块封装的应用
检查更新-》下载文件-》升级替换-》应用新模块
.NET中的程序集
什么是程序集
-
程序集是.NET Framework中基本的软件模块(包含编译好的代码的逻辑单元),其常见的载体为一个或多个dll(动态链接库)文件,也可以是一个可独立执行的exe文件
-
类库项目、Winform程序、WPF程序、控制台程序、WebForm程序等都是程序集
程序集的信息
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("计算器")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("英莱特信息科技有限公司")]
[assembly: AssemblyProduct("计算器软件")]
[assembly: AssemblyCopyright("InLett@ 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("d2682640-a488-4b23-b058-1339533eb1e4")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
或者:应用程序鼠标右键-》属性-》程序集信息
多语言编程
通过程序集能够有效实现
例如:客户提出新的问题:计算器类由程序员A编写,但是A程序员只会VB.NET语言,但是目前程序员B只会C#语言,加入你是A如何做?
解决:和之前的解决方案一致,使用VB.NET开发好类库项目,然后生成一个dll文件发送给B使用
原理分析
回顾.NET平台的构成
VS提供的开发语言:VB、C#、C++等各类程序(网站、软件)
以上的所有语言都是运行在.NET Framework类库--完成的是程序开发组件(半成品)
这些程序运行的环境是公共语言运行时(CLR)---相当于这些语言运行的一个虚拟机
.NET Framework包含的两部分内容
-
.NET Framework类库:Winform、Webform、WPF、MVC、WCF、……
ADO.NET和XML类、IO流类……
基础框架类
-
公共语言运行库CLR(.NET虚拟机)
CLS公共语言规范
CTS通用类型系统
核心原理
-
CTS(Common Type System)
定义了在IL中的数据类型
消除了不同开发语言之间的“数据类型”的差别
-
CLS(Common Languages Specification)
定义了在IL中的语法规则
消除了不同开发语言之间的“语法”差别
以上原因正是因为CTS和CLS才能使得不同语言了开发的程序集模块都能够编译成微软的中间语言(msil),所以他们之间可以无缝集成的使用