C#中异常使用的注意事项

简介:

C#中异常使用的注意事项

一:两个立足点

1:正常控制流程下的代码运行并不会带来问题,只有引发异常才会带来效率问题。

2:不应将异常机制用于正常控制流中。


二:需要引发异常的四类情况

第一类情况是:如果运行代码后,造成内存泄漏、资源不可用或应用程序状态不可恢复,则引发异常。Console这个类中,有很多类似这样的代码: 


  
  
if ((value < 1 ) || (value > 100 ))
{
throw new ArgumentOutOfRangeException( " value " , value, Environment.GetResourceString( " ArgumentOutOfRange_CursorSize " ));
}

Console这个类虽然也提供了Tester-Doer模式,让调用者可以有更多的方法来验证输入。但是永远不要保证调用者对你的类有足够的了解,他有可能调用你的任何公开方法,而不会考虑先后顺序;所以应该为这类方法引发一些必要的异常。但是,如果你自己写了一个Student业务类,判断年龄,年龄小于0这样的判断,就不应该引发异常,因为那是一个正常控制流。

第二类需要引发异常的情况是:在捕获异常的时候,如果需要包装一些更有用的信息,则引发异常。这类异常的引发在UI层特别有用。系统引发的异常所带的Message往往更倾向于技术性的描述,而在UI层,异常的用户很可能是最终用户。如果我们需要将异常的Message信息呈现给最终用户,更好的做法是包装异常,然后引发一个含有友好信息的新异常。

第三类情况:如果底层异常在高层操作的上下文中没有意义,则可以考虑捕获这些底层异常,并引发新的有意义的异常。如将一个InvalidCastException引发为新的ArgumentException。

第四类正确引发异常的一个典型的例子就是捕获底层API错误代码,并抛出。Console为我们封装了调用windows api返回的错误代码,而让代码引发一个新的异常。

 

三:避免throw中将异常堆栈信息吃掉

代码应该看起来是这样的:

复制代码
代码

   
   
try
{
(
new NestedExceptionSample2()).MethodWithTry2();
}
catch (Exception)
{
// do something
throw ;
}
复制代码

或者:

复制代码
代码

   
   
try
{
(
new NestedExceptionSample2()).MethodWithTry2();
}
catch
{
// do something
throw ;
}
复制代码

尽量避免像下面这样引发异常:


  
  
catch (Exception err)
{
// do something
throw err;
}

直接throw err而不是throw将会重置堆栈信息。

 

四:处理未捕获异常和多线程异常

这在我的另一篇博文中已经论述:异常处理之ThreadException、unhandledException及多线程异常处理


五:避免在调用栈较低位置记录异常

最适合进行异常记录和报告的是应用程序的最上层,这通常是UI层。假设存在这样的一个应用程序,它的BLL层,即可能被一个Winform窗口程序调用,也可能被一个控制台应用程序调用,那么如果要在BLL模块向管理员报告异常的时候,你不知该使用MessageBox方法还是Console.Write方法。

如果异常在调用栈的较低位置被记录或报告,且还存在被包装后重新抛出的情况,这就会让记录重复出现。

 

六:推荐总是使用FCL异常

也即慎用自定义异常。需要自定义异常的理由如下:

1:方便调试,通过抛出一个我们自己定义的异常类型实例,我们可以使捕获代码精确地知道所发生的事情,并以合适的方式进行恢复。

2:逻辑包装,自定义异常可包装多个其它异常,然后抛出一个业务异常。 

3:方便调用者编码,在编写自己的类库或者业务层代码的时候,自定义异常可以让调用方更方便处理业务异常逻辑。如保存数据失败,可以分成两个异常"数据库连接失败。"、"网络异常。" 

4:引入新异常类,使程序员能够根据异常类在代码中采取不同的操作。

 

七:不要再从System.ApplicationExcetipn这个基类派生异常

微软自己也已经修正这一点,当前的建议是:从System.Exception或其它常见基本异常之一派生异常。事实上,现在如果你在Visual studio中输入Excetion,然后使用快捷键tab,vs会自动给你创建一个继承自System.Exception的自定义异常类

 

八:避免在finally撰写无效代码

需要先提出一个问题,即:是否存在一种打破try-finally执行顺序的情况。答案是:没有(除非应用程序本身因为某些很少出现的特殊情况在try块中退出)。你应该始终认为finally内代码会在方法return之前被执行,哪怕return是在try块中。

但,需要区分引用类型变量和值类型变量在finally中会导致不同结果。 

复制代码
代码

   
   
private static int TestIntReturnInTry()
{
int i;
try
{
return i = 1 ;
}
finally
{
i
= 2 ;
Console.WriteLine(
" \t将int结果改为2,finally执行完毕 " );
}
}
复制代码

它返回的将是1。代码中,i=2实际上是一段无效代码,如果编译采用Release模式,编译器会直接将i=2删除,它不会为其生成对应的IL代码。

但是: 

复制代码
代码

   
   
static User TestUserReturnInTry()
{
User user
= new User() { Name = " Mike " , BirthDay = new DateTime( 2010 , 1 , 1 ) };
try
{
return user;
}
finally
{
user.Name
= " Rose " ;
user.BirthDay
= new DateTime( 2010 , 2 , 2 );
Console.WriteLine(
" \t将user.Name改为Rose " );
}
}
复制代码

我们会发现,TestUserReturnInTry方法返回的User中,Name的值已经改变为Rose了。


本文转自最课程陆敏技博客园博客,原文链接:http://www.cnblogs.com/luminji/archive/2011/01/08/1930536.html,如需转载请自行联系原作者

相关文章
|
4月前
|
安全 测试技术 数据库连接
如何避免 C# 中的异常
【8月更文挑战第27天】
57 2
|
4月前
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
57 0
|
6月前
|
开发框架 .NET 程序员
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
34 0
|
7月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
358 2
|
7月前
|
安全 编译器 C#
C#中的可空引用类型:减少空引用异常的利器
【1月更文挑战第9天】C# 8.0中引入的可空引用类型特性,它通过在编译时提供更精确的静态分析,帮助开发者减少运行时的空引用异常。文章详细阐述了可空引用类型的工作原理、如何配置项目以使用此特性,以及在实际编码中如何利用可空引用类型提升代码的健壮性和可读性。
|
开发框架 JSON 前端开发
【C#】.net core2.1,自定义全局类对API接口和视图页面产生的异常统一处理
在开发一个网站项目时,异常处理和过滤功能是最基础的模块 本篇文章就来讲讲,如何自定义全局异常类来统一处理
241 0
|
C# 数据处理
C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)
原文:C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值) 1、问题的提出: 电池生产中,遇到一批电池的测量结果数据: 电压值 电池个数 电压值 电池个数 电压值 电池个数 电压值 电池个数 0.
1759 0
C#(二十六)之C#异常
异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。C# 异常处理时建立在四个关键词之上的:try、catch、finally 和 throw。
125 0
C#(二十六)之C#异常
|
C#
C#多线程开发-处理异步操作中的异常
C#多线程开发-处理异步操作中的异常
193 0