前言  

  本文已同步到http://www.cnblogs.com/aehyok/p/3624579.html。本文主要来学习以下几点建议

  建议61、避免在finally内撰写无效代码

  建议62、避免嵌套异常

  建议63、避免“吃掉”异常

  建议64、为循环增加Tester-Doer模式而不是将try-catch置于循环内

建议61、避免在finally内撰写无效代码

先直接来看一下三个简单的try catch方法

    public class User
{
public string Name { get; set; }
} class Program
{ static void Main(string[] args)
{
Console.WriteLine(Test1());
Console.WriteLine(Test2());
Console.WriteLine(Test3().Name); Console.ReadLine();
} public static int Test1()
{
int i = ;
try
{
i = ;
}
finally
{
i = ;
Console.WriteLine("\t 将int结果改为2,finnally执行完毕。");
}
return i;
} public static int Test2()
{
int i = ;
try
{
return i = ;
}
finally
{
i = ;
Console.WriteLine("\t 将int结果改为2,finnally执行完毕。");
}
}

看完代码你心里大概也有了一个答案了吧

这些如果通过IL来解释,还是比较容易的,在此就不进行赘述了。

  在CLR中,方法的参数以及返回值都是用栈来保存的。在方法内部,会首先将参数依次压栈,当需要使用这些参数的时候,方法会直接去栈里取用参数值,方法返回时,会将返回值压入栈顶。如果参数的类型是值类型,压栈的就是复制的值,如果是引用类型,则在方法内对于参数的修改也会带到方法外。

建议62、避免嵌套异常  

在建议59中已经强调过,应该允许异常在调用堆栈中往上传播,不要过多使用catch,然后再throw。果断使用catch会带来两个问题:

1、代码更多了。这看上去好像你根本不知道该怎么处理异常,所以你总在不停地catch.

2、隐藏了堆栈信息,使你不知道真正发生异常的地方。

来看一下下面的代码

        static void Main(string[] args)
{
try
{
Console.WriteLine("NoTry\n");
MethodNoTry();
}
catch (Exception exception)
{
Console.WriteLine(exception.StackTrace);
}
try
{
Console.WriteLine("WithTry\n");
MethodWithTry();
}
catch (Exception exception)
{
Console.WriteLine(exception.StackTrace);
}
Console.ReadLine();
} public static int Method()
{
int i = ;
return / i;
} public static void MethodNoTry()
{
Method();
} public static void MethodWithTry()
{
try
{
Method();
}
catch (Exception exception)
{
throw exception;
}
}

执行结果

  可以发现,MethodNoTry的方法可以查看到发生异常错误的地方,而MethodWithTry根本不清楚发生错误的地方了。调用的堆栈倍重置了。如果这个方法还存在另外的异常,在UI层将永远不知道真正发生错误的地方,给开发者带来不小的麻烦。 

除了在建议59中提到的需要包装异常的情况外,无故地嵌套异常是我们要极力避免的。当然,如果真得需要捕获这个异常来恢复一些状态,然后重新抛出,代码来起来应该可以这样:

            try
{
MethodWithTry();
}
catch(Exception)
{
///工作代码
throw;
}

或者稍作改动

            try
{
MethodWithTry();
}
catch
{
///工作代码
throw;
}

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

            try
{
MethodWithTry();
}
catch(Exception exception)
{
///工作代码
throw exception;
}

直接throw exception而不是throw将会重置堆栈消息。

建议63、避免“吃掉”异常 

  看了建议62之后,你可能已经明白,嵌套异常是很危险的行为,一不小心就会将异常堆栈信息,也就是真正的Bug出处隐藏起来。但这还不是最严重的行为,最严重的就是“吃掉”异常,即捕获然后不向上层throw抛出。

  避免“吃掉”异常,并不是说不应该“吃掉”异常,而是这里面有个重要原则:该异常可悲预见,并且通常情况它不能算是一个Bug。

  想象你正在对上万份文件进行解密,这些文件来自不同的客户端,很有可能存在文件倍破坏的现象,你的目标就是要讲解密出来的数据插入数据库。这个时候,你不得不忽略那些解密失败的问题,让这个过程进行下去。当然,记录日志是必要的, 因为后期你可能会倍解密失败的文件做统一的处理。

  另外一种情况,可能连记录日志都不需要。在对上千个受控端进行控制的分布式系统中,控制端需要发送心跳数据来判断受控端的在线情况。通常的做法是维护一个信号量,如果在一个可接受的阻滞时间如(如500ms)心跳数据发送失败,那么控制端线程将不会收到信号,即可以判断受控端的断线状态。在这种情况下,对每次SocketException进行记录,通常也是没有意义的。

  本建议的全部要素是:如果你不知道如何处理某个异常,那么千万不要“吃掉”异常,如果你一不小“吃掉”了一个本该网上传递的异常,那么,这里可能诞生一个BUg,而且,解决它会很费周折。

建议64、为循环增加Tester-Doer模式而不是将try-catch置于循环内

  如果需要在循环中引发异常,你需要特别注意,因为抛出异常是一个相当影响性能的过程。应该尽量在循环当中对异常发生的一些条件进行判断,然后根据条件进行处理。可以做一个测试:

        static void Main(string[] args)
{
CodeTimer.Initialize(); CodeTimer.Time("try..catch..", , P1); CodeTimer.Time("Tester-Doer", , P2); Console.ReadLine();
} public static void P1()
{
int x = ;
for (int i = ; i < ; i++)
{
try
{
int j = i / x;
}
catch
{ }
}
}

差距相当明显。以上代码中,我们预见了代码可能会发生DivideByZeroException异常,于是,调整策略,对异常发生的条件进行了特殊处理:Continue,让效率得到了极大的提升。

英语小贴士

1、 How much?—— 多少钱?
2、I'm full.—— 我饱了。
3、 I'm home.—— 我回来了。
4、 I'm lost. ——我迷路了。
5、 My treat.—— 我请客。
6、 So do I.—— 我也一样。
7、 This way.—— 这边请。
8、 After you.—— 您先。
9、 Bless you! ——祝福你!
10、 Follow me.—— 跟我来。

作者:aehyok

出处:http://www.cnblogs.com/aehyok/

感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,那不妨点个推荐吧,谢谢支持:-O。

编写高质量代码改善C#程序的157个建议[避免finaly内的无效代码、避免嵌套异常、避免吃掉异常、注意循环异常处理]的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议——建议15: 使用dynamic来简化反射实现

    建议15: 使用dynamic来简化反射实现 dynamic是Framework 4.0的新特性.dynamic的出现让C#具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,编译器默认dy ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. VS2010 调试窗口一闪而过解决方法

    若此时进行的操作是编译(F5),可先运行程序(Ctrl+F5),若仍然一闪而过,用下面方法解决. 方法一: 1.要有头文件cstdlib,在程序最后写一句(return之前)添加:system(&qu ...

  2. SSIS with vertica

    使用ODBC进行连接,因为SSIS中没有直接的ODBC connection,所以使用ADO.NET的连接器. 九分钟才跑了四百来条数据. 这个图反应了SSIS的数据流速度还是可以的,但是瓶颈就在OD ...

  3. 自定义input[type="file"]的样式

    input[type="file"]的样式在各个浏览器中的表现不尽相同: 1. chrome: 2. firefox: 3. opera: 4. ie: 5. edge: 另外,当 ...

  4. noip2014提高组day2二题题解-rLq

    (又是昨天的作业……本题写于昨天) (这破题都做这么久,我是不是吃枣药丸……) (好吧这是一道图论题呢) 本题地址:http://www.luogu.org/problem/show?pid=2296 ...

  5. 【Android Demo】简单手机通讯录

    Android 系统给我们提供了访问通讯录的接口,通过接口获取通讯录信息.Adapter 与 View 的连接主要依靠 getView 这个方法返回我们需要的自定义 view. ListView 是 ...

  6. 2016百度之星-初赛(Astar Round2A)AII X

    Problem Description F(x,m) 代表一个全是由数字x组成的m位数字.请计算,以下式子是否成立: F(x,m) mod k ≡ c Input 第一行一个整数T,表示T组数据. 每 ...

  7. Android studio导入eclipse项目混淆打包出错

    将proguard-android.txt复制一份重命名成proguard-rules.pro,且在build.gradle添加 release {             minifyEnabled ...

  8. 微服务架构:Eureka集群搭建

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 服务注册.发现是微服务架构的关键原理之一,由于微服务架构是由一系列职责单一的细粒度服务构成的网状结构,服务之间通过轻量机制进行通信,这就必 ...

  9. tcpdump参数应用

    详细参数: http://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html 我用到的参数: 一 tcpdump重要参数 -i 指定监听 ...

  10. U3D5.3.5f Monodevelop 仅支持到.NET 3.5

    2016年12月2号:发现这个标题是错误的,可以在monodevelop中选择.NET的版本,如下:打开solution,右击 Assembly-CSharp,options, build, gene ...