建议58:用抛出异常代替返回错误代码

CLR异常机制的优点:

  • 正常控制流会被立即中止,无效值或状态不会在系统中继续传播。
  • 提供了统一的处理错误的方法。
  • 提供了在构造函数、操作符重载及属性中报告异常的遍历机制。
  • 提供了异常堆栈,便于开发者定位异常发生的位置。

不应该将异常机制用于正常控制流中,异常的发生是一个小概率事件,所以异常带来的效率问题会被限制在一个很小的范围内。异常机制带来的效率问题不足以抵消它带来的巨大收益。try catch所带来的效率问题几乎是可以忽略的。

在异常机制出现之前,应用程序普遍采用错误代码的方式来通知调用之发生了异常。为什么要用抛出异常代替返回错误代码呢?

对于一个成员方法而言,它要么执行成功,要么执行失败。成员方法执行成功的情况很容易理解,但如果执行失败了却没有那么简单,因为我们需要将执行失败的原因通知调用者。抛出异常和返回错误代码都是用来通知调用者的手段。

假如我们要实现一个点单的功能:应用程序要完成一次保存新建用户的操作。这是一个分布式的操作,保存动作除了需要将用户保存在本地外,还需要通过WCF在远程服务器上保存数据。负责保存用户的成员如下:

        private static int SaveUser1(User user)
{
if (!SaveToFile(user))
{
return ;
}
if (!SaveToDataBase(user))
{
return ;
}
return ;
}

代码看似没有问题的,调用者只要接收到1或2,就知道是哪里出现了问题,但如果执行失败,似乎还可以挖掘出更多的原因:

在SaveToFile方法中,我们可能会遇到:

  • 程序无数据存储文件写权限导致的失败。
  • 硬盘空间不足导致的失败。

在SaveToDataBase方法中,可能会遇到:

  • 服务不存在导致的失败。
  • 网络连接不正常导致的失败。

当我们想要告示调用者更多细节的时候,就需要与调用者约定更多的错误代码。于是。错误代码飞速膨胀,直到看起来似乎无法维护,因为我们总是查找并确认错误代码。

采用接下来的方法,可能会省略很大一部分的错误代码:

        private static bool SaveUser2(User user,ref string errorMsg)
{
if (!SaveToFile(user))
{
errorMsg = "本地保存失败!";
return false;
}
if (!SaveToDataBase(user))
{
errorMsg = "远程保存失败!";
return false;
}
return true;
}

在没有异常处理前,我们只能返回错误代码。但是,现在有了另一种选择,既使用异常机制。如下:

        private static void SaveUser(User user)
{
SaveToFile(user);
SaveToDataBase(user);
} static void Main(string[] args)
{
User user = new User();
try
{
SaveUser(user);
}
catch (IOException)
{
//IO异常,通知当前用户
}
catch (UnauthorizedAccessException)
{
//权限失败,通知客户端管理员
}
catch (CommunicationException)
{
//网络异常,通知发送e-mail给网络管理员。
} }

使用了CLR异常机制后,代码更加清晰,易于理解。至于效率问题,throw exception产生的那点儿效率损失与等待网络连接异常相比,简直微不足道,而CLR异常机制带来的好处却是显而易见的。

在catch (CommunicationException)代码块中,代码所完成的功能是“通知发送”,而不是“发送”本身,因为我们需要确保在catch和finally中所执行的代码是可以被执行的。尽量不要在catch和finally中再让代码“出错”,那会让异常堆栈信息变得复杂和难以理解。

在本例中的catch代码块中,不是要真的编写发送邮件的代码,因为发送邮件的这个行为可能会产生更多的异常,而“通知发送”这个行为稳定性更高(即“不出错”)。

在某些情况下,错误代码将无用武之地,如构造函数、操作符重载及属性。语法的特性决定了其不具备任何返回值,于是异常处理被当做取代错误代码的首要选择。

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

编写高质量代码改善C#程序的157个建议——建议58:用抛出异常代替返回错误代码的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  6. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  7. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  8. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  9. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  10. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. 【转】JMeter入门

    一.JMeter概述 JMeter就是一个测试工具,相比于LoadRunner等测试工具,此工具免费,且比较好用,但是前提当然是安装Java环境: JMeter可以做 (1)压力测试及性能测试: (2 ...

  2. java分割函数split的用法(二)

    package com.b; public class Sysetm { public static void main(String[] args) { String a=new String(&q ...

  3. chrome浏览器手动添加印象笔记剪藏插件

    标签(空格分隔): chrome浏览器,日常办公 一直为每次从网页上复制内容之后,还需要再去复制对应的网址,倍感麻烦.之前偶尔这样操作还可以,最近在学习新东西,要保留下来的网页实在太多,而且不利于分类 ...

  4. 转:oracle几组重要的常见视图-v$process,v$session,v$session_wait,v$session_event

    v$process 本视图包含当前系统oracle运行的所有进程信息.常被用于将oracle或服务进程的操作系统进程ID与数据库session之间建立联系.在某些情况下非常有用: 1 如果数据库瓶颈是 ...

  5. 爬取github上流行的python项目

    # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import requests from pyquery import PyQ ...

  6. Pandas:表计算与数据分析

    目录 Pandas之Series Pandas之DataFrame 一.pandas简单介绍 1.pandas是一个强大的Python数据分析的工具包.2.pandas是基于NumPy构建的. 3.p ...

  7. SerialPort缓冲区

    SerialPort缓冲区中有:接收缓冲区,发送缓冲区,输入缓冲区,输出缓冲区,传输缓冲区. 例如: 串口属性:BytesToRead(获取接收缓冲区中数据的字节数)--这里提到的是“接收缓冲区” 串 ...

  8. JasperMES.cn JasperMES.com.cn 我的MES网站

    好久没有更新博客园.今天写上两面的两个网址JasperMES.cn JasperMES.com.cn是想记录我在做上面两个网站时的一点心得. 老实说,现在建站的软件很多,WordPress,CMS,我 ...

  9. 闲来无事,做做Google:21 道能力倾向测试面试题

    1. Solve this cryptic equation, realizing of course that values for Mand E could be interchanged. No ...

  10. 06-Location详解之精准匹配

    之前nginx不是编译过吗?现在重新make install一下. 刚刚这个是我们新安装的.原始版的nginx,配置文件比较少,便于我们做调试. 试试精准匹配的概念. 匹配的是/.优先匹配这个最精准的 ...