<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_老刘忙不忙</title><subtitle type="text">很忙</subtitle><id>http://feed.cnblogs.com/blog/u/31032/rss</id><updated>2011-07-11T01:57:25Z</updated><author><name>老刘很氓</name><uri>http://www.cnblogs.com/xd125/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xd125/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/31032/rss"/><entry><id>http://www.cnblogs.com/xd125/archive/2011/07/08/2100973.html</id><title type="text">谈谈异常处理策略</title><summary type="text">Hi, All在这里对我知道的异常处理和大家分享一下，不足的地方请大家补充一．异常发生的原因：我们的程序往往有很多依赖，这些依赖是异常发生源，它们包括：1. 外部系统(数据库，Remoting,WebService等)2. 外部文件(配置文件，数据文件)3. 他人写的类库，函数，.NET FRAMEWORK类库自身。二．什么时候抓住异常仅当以下一种或多种情况时，我们的代码才需要抓住异常1. 记录异常(logging)将异常记录到日志中，便于support人员查找错误原因。2. 为这个异常添加相关信息(wrap exception)加发生异常的环境信息记录，并产生新异常，交给调用本方法的代码负责</summary><published>2011-07-08T06:44:00Z</published><updated>2011-07-08T06:44:00Z</updated><author><name>老刘很氓</name><uri>http://www.cnblogs.com/xd125/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xd125/archive/2011/07/08/2100973.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xd125/archive/2011/07/08/2100973.html"/><content type="html">&lt;div&gt;&lt;div&gt;Hi, All&lt;/div&gt;&lt;div&gt;在这里对我知道的异常处理和大家分享一下，不足的地方请大家补充&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;一．异常发生的原因：&lt;/div&gt;&lt;div&gt;我们的程序往往有很多依赖，这些依赖是异常发生源，它们包括：&lt;/div&gt;&lt;div&gt;1. &amp;nbsp; &amp;nbsp; &amp;nbsp; 外部系统(数据库，Remoting,WebService等)&lt;/div&gt;&lt;div&gt;2. &amp;nbsp; &amp;nbsp; &amp;nbsp; 外部文件(配置文件，数据文件)&lt;/div&gt;&lt;div&gt;3. &amp;nbsp; &amp;nbsp; &amp;nbsp; 他人写的类库，函数，.NET FRAMEWORK类库自身。&lt;/div&gt;&lt;div&gt;二．什么时候抓住异常&lt;/div&gt;&lt;div&gt;仅当以下一种或多种情况时，我们的代码才需要抓住异常&lt;/div&gt;&lt;div&gt;1. &amp;nbsp; &amp;nbsp; &amp;nbsp; 记录异常(logging)&lt;/div&gt;&lt;div&gt;将异常记录到日志中，便于support人员查找错误原因。&lt;/div&gt;&lt;div&gt;2. &amp;nbsp; &amp;nbsp; &amp;nbsp; 为这个异常添加相关信息(wrap exception)&lt;/div&gt;&lt;div&gt;加发生异常的环境信息记录，并产生新异常，交给调用本方法的代码负责处理。&lt;/div&gt;&lt;div&gt;3. &amp;nbsp; &amp;nbsp; &amp;nbsp; 执行清理工作&lt;/div&gt;&lt;div&gt;比如关闭数据库连接，Dispose对象，Rollback，Compensate操作等。&lt;/div&gt;&lt;div&gt;4. &amp;nbsp; &amp;nbsp; &amp;nbsp; 尝试从异常中恢复&lt;/div&gt;&lt;div&gt;比如程序可以取一个默认值让程序继续进行(上次举过实时显示设备温度的程序的例子，当程序请求设备，但设备有时会因为响应&lt;/div&gt;&lt;div&gt;超时导致程序异常，这是程序可以捕捉这个异常，以上次取得的温度结果显示给用户)&lt;/div&gt;&lt;div&gt;常见的例子还有数据库连接突然断掉，或者插入数据时主键冲突(有可能是输入错误，也有可能同一条数据被别的用户先插入到数据库了)。&lt;/div&gt;&lt;div&gt;5. &amp;nbsp; &amp;nbsp; &amp;nbsp; 隐藏异常敏感信息，替换成友好信息给用户。&lt;/div&gt;&lt;div&gt;三．异常传播&lt;/div&gt;&lt;div&gt;如果一个方法不需要做二提到的5件事情，或者说是需要将怎样处理异常的决定权交给其他模块(比如数据库并发异常，怎么处理应该是业务逻辑的事)，&lt;/div&gt;&lt;div&gt;这时我们就需要让这个异常传播出去，而不是Catch，更不能Catch住后什么事情都不做，直接让异常神秘的消失（这点是让人最痛苦的）， &amp;nbsp; 这样可以保持代码清洁明了。&lt;/div&gt;&lt;div&gt;传播异常的途径有三种：&lt;/div&gt;&lt;div&gt;1. &amp;nbsp; &amp;nbsp; &amp;nbsp; 直接传播&lt;/div&gt;&lt;div&gt;忽略异常处理，让调用栈上的其他方法来处理。&lt;/div&gt;&lt;div&gt;2. &amp;nbsp; &amp;nbsp; &amp;nbsp; Catch并且rethrow&lt;/div&gt;&lt;div&gt;抓住异常，执行清理，或者其他一些当前方法中能做的处理（前面提到的日志之类），如果异常不能恢复，并且当前方法并不是消除异常的好地方，重新抛出异常。&lt;/div&gt;&lt;div&gt;3. &amp;nbsp; &amp;nbsp; &amp;nbsp; Catch 并且包装Exception，并且重新抛出。&lt;/div&gt;&lt;div&gt;有时我们为了隐藏内部实现，或者让异常类型更符合当前调用链的层次&lt;/div&gt;&lt;div&gt;(比如对于Biz层抛出异常时，名为BizProcessException就比具体的原始的SqlException要好理解。&lt;/div&gt;&lt;div&gt;再比如我们写了一个Web service供外部人员调用，我们不希望所有的异常信息暴露给外部调用人员，这时我们也需要构建一个新的Exception来告知用户，提示他可以怎样处理这个异常，是可以恢复的还是不可以恢复的等等)&lt;/div&gt;&lt;div&gt;但是我们同时为了保留原始的Exception便于更精确的处理它，我们可以使用Exception的InnerException来保留原来的Exception&lt;/div&gt;&lt;div&gt;需要提醒大家的是，新建异常按照编码规范最好继承与ApplicationException。&lt;/div&gt;&lt;div&gt;四．处理异常的指导意见：&lt;/div&gt;&lt;div&gt;1. &amp;nbsp; &amp;nbsp; &amp;nbsp; 除非是第二点处提到的时候，其他时候不要处理异常&lt;/div&gt;&lt;div&gt;2. &amp;nbsp; &amp;nbsp; &amp;nbsp; 在程序里的边界处处理异常(比如逻辑层的最上面一层，调用的服务处，UI等),并且屏蔽掉敏感信息，只保留对当前层次安全的信息。&lt;/div&gt;&lt;div&gt;3. &amp;nbsp; &amp;nbsp; &amp;nbsp; 通过自定义异常的名字来表达异常类型，应该怎么处理，是否能恢复。&lt;/div&gt;&lt;div&gt;4. &amp;nbsp; &amp;nbsp; &amp;nbsp; 不要一大段的try,接着就是catch(Exception ex),应根据代码中可能发生的异常(查阅MSDN或者服务调用文档)精确分类处理，为了避免遗漏，可以这样处理：&lt;/div&gt;&lt;div&gt;Try&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp;// exception here&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;Catch(ConnectionException ex)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // handle connect error;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;Catch(AccessDenyException ex)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; //handle access deny error&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;Catch(Exeption ex)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; //handle generic exception&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;5. &amp;nbsp; &amp;nbsp; &amp;nbsp; 不要抓住异常后，什么处理都不做，直接抛出，例如：&lt;/div&gt;&lt;div&gt;Try&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;// exception here&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;Catch(Exception ex)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;Throw ex;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;这么做会让异常的堆栈信息是从Throw这行开始，而不是真正异常发生的地方，为将来查错带来不便。&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;6. &amp;nbsp; &amp;nbsp; &amp;nbsp; 将异常提示给用户时，应该显示友好信息，并提供建议的做法，不应包括敏感信息如调用堆栈，服务器名等。&lt;/div&gt;&lt;div&gt;7. &amp;nbsp; &amp;nbsp; &amp;nbsp; 为了support的方便，我们可以为提示给用户的异常信息安插一个异常处理ID，用户可以很方便的把这个ID拷贝下来并邮件发送给support人员，&lt;/div&gt;&lt;div&gt;Support人员根据这个ID去日志文件中查找这个ID相关联的异常记录，如图：&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;日志文件记录：&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div&gt;8. &amp;nbsp; &amp;nbsp; &amp;nbsp;引入异常处理框架和策略注入框架完善，简化异常处理。&lt;/div&gt;&lt;div&gt;比如：PolicyInjection.Create&amp;lt;TestPolicyInjection,ITestPolicyInjection&amp;gt;().GetData();&lt;/div&gt;&lt;div&gt;GetData()方法中并没有任何异常处理代码，但是，它却做了以下事情：&lt;/div&gt;&lt;div&gt;如果发生数据库连接异常，记录日志并抛出warp exception :DBConnectionException，&lt;/div&gt;&lt;div&gt;如过是主键冲突，记录日志并抛出wrap exception: DuplicateRecordException&amp;nbsp;&lt;/div&gt;&lt;div&gt;这是采用面向方面编程的一种策略实现，有兴趣的同学可以查看：http://msdn.microsoft.com/en-us/library/aa288717(VS.71).aspx&lt;/div&gt;&lt;div&gt;9. &amp;nbsp; &amp;nbsp; &amp;nbsp; 对于一般情况不可能发生的事情的地方（但或许是外部系统的不正确，内部的配置不正确，环境的不正确等问题导致又有可能导致发生），用Debug.Assert处理&lt;/div&gt;&lt;div&gt;例,在XXXXX里面有一段代码逻辑是去取当前用户的NO，这个No是标识在机器名的第二位(此处无任何注释，我揣摩了很久)&lt;/div&gt;&lt;div&gt;但是我们调试时，仓库是自己插入的，曾经有段时间我把位置记错，导致代码执行到一个很远的地方时才报异常，我跟踪了半天，才发现是这个问题，&lt;/div&gt;&lt;div&gt;如果在取这个No这个代码里用断言提示的话，应该能让程序员很快知道问题所在：&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; public static string GetWareHouseNumberInHostName(this string hostName)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Int16 &amp;nbsp;parseNumber = 0;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; bool parseToNumerSucced = Int16.TryParse(hostName.Substring(1, 2), out parseNumber);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (!parseToNumerSucced)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; parseToNumerSucced = Int16.TryParse(hostName.Substring(1, 1), out parseNumber);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.Diagnostics.Debug.Assert(parseToNumerSucced,"host name doesen't contain warehouse number");&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return parseNumber.ToString("D2");&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;再比如，配置文件未正确配置，数据库某字段不能为空，但是建表时又未该字段加以限制，结果由于数据不正确导致程序异常这些情况，我们也可以在代码里先用断言确保一下正确性。&lt;/div&gt;&lt;p&gt;五．异常处理策略(High level Design)：见下面两张图，截取自Enterprise Library 说明文档，大家可以有个直观的感受:&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/xd125/ExceptionHandling.GIF" border="0" alt="" width="688" height="608" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;六.列举一个实际项目的例子:&lt;/p&gt;&lt;p&gt;待续....&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/xd125/aggbug/2100973.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/xd125/archive/2011/07/08/2100973.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/xd125/archive/2007/12/12/992406.html</id><title type="text">c# 线程同步： 详解lock,monitor,同步事件和等待句柄以及mutex</title><summary type="text">详细介绍lock,monitor,同步事件和等待句柄以及mutex的使用方法以及注意事项</summary><published>2007-12-12T08:44:00Z</published><updated>2007-12-12T08:44:00Z</updated><author><name>老刘很氓</name><uri>http://www.cnblogs.com/xd125/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xd125/archive/2007/12/12/992406.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xd125/archive/2007/12/12/992406.html"/></entry><entry><id>http://www.cnblogs.com/xd125/archive/2007/11/23/969970.html</id><title type="text">在DataAdapter中开启事务</title><summary type="text">利用System.Reflection命名空间下的PropertyInfo类的GetProperty方法取得table adapter的私有connection属性，附加上transaction对象后，再通过PropertyInfo的SetValue方法将改造后的connection属性设置回table adapter实例</summary><published>2007-11-23T07:07:00Z</published><updated>2007-11-23T07:07:00Z</updated><author><name>老刘很氓</name><uri>http://www.cnblogs.com/xd125/</uri></author><link rel="alternate" href="http://www.cnblogs.com/xd125/archive/2007/11/23/969970.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/xd125/archive/2007/11/23/969970.html"/></entry></feed>
