zoukankan      html  css  js  c++  java
  • 读书笔记—CLR via C#异常和状态管理

    前言

    这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可以加深自己理解的深度,当然同时也和技术社区的朋友们共享

    Tips

    • vs调试catch块时,监视窗口变量: $exception 查看当前抛出的异常对象
    • 异常的catch是自上而下,回溯调用栈,如果未找到,就抛出未处理异常
    • 异常的执行顺序:先执行body,再执行catch,最后执行finally
    • 堆栈异常的执行顺序:ParentBody ChildBody ChildCatch ChildFinally ParentCatch ParentFinally
    • .NET 4版本及后续版本中,可向AppDomain的FirstChanceException登记Appdomain中发生的第一次异常捕获,它发生在CLR搜索任何catch块之前
    • finally中的代码保证会被执行,无论异常是否发生(用Win32函数TerminateThread杀死线程,或者用Winb32函数TerminateProcess或System.Environment的FailFast方法杀死进程,finally块不会执行。当然进程终止后,Windows会清理进程使用的所有资源)
    • 如果catch或者finally中抛出异常,原有异常会丢失,新的异常继续向上回溯
    • CLR只能捕获CLS相容(从Exception派生的异常被认为时CLS相容的)的异常,如果C#调用另一种编程语言的方法,抛出非CLS相容的异常,那么C#代码不能捕捉这个异常,这会有一些安全隐患
    • 非CLS相容的一个异常被抛出时,CLR会自动构造RuntimeWrappedException类的实例,并初始化该实例的私有字段,使之引用实际抛出的对象。这样一来CLR就将非CLS相容的异常转变成了CLS相容的异常。所以任何能捕捉Exception类型的代码,都能捕捉非CLS相容的异常,从而消除了安全隐患
    • 在C#2.0之后,Catch可以捕捉CLS相容和不相容的任何异常(Exception),而如果直接catch{} ,所以版本的C#都可以捕捉CLS相容和不相容异常
    • 如果要兼容CLR旧的行为[assembly:RuntimeCompatibility(WrapNonExceptionThrows=false)]
    • 一个异常抛出时,CLR会在内部记录throw指令的位置(抛出位置),一个catch捕捉到异常时,CLR又会记录异常的捕捉位置
    • 在catch块内访问被抛出的异常对象的StackTrace属性,负责实现该属性的代码会调用CLR内部代码,创建一个字符串指出从异常抛出位置道异常捕捉位置的所有方法
    • 在catch中重写throw e会重置异常的起点(重置堆栈的起点),不符合编码规范,如果仅仅使用throw 则OK
    • 如果代码方法被内联,可能导致异常堆栈跟踪不准确对应到源代码,如果要防止JIT优化内联,使用编译器开关 /debug 或者[System.Runtime.CompilerServices.MethodImplAttribute(MethodImplOptions.NoInling)]
    • 异常自身字符串消息可以包含详细的技术细节,用于跟踪调试,但这些消息不应该直接让应用层捕获,不应该向最终用户显示
    • FCL的异常消息都使用了本地化字符串,开发人员可以根据实际情况考虑
    • 设计和处理异常时,通常要牺牲可靠性来换取开发效率
    • 尽量避免捕捉System.Exception然后允许应用程序继续允许,一个很大的问题是状态可能遭受破坏
    • lock, using和foreach语句,都使用了try/finally块,重写析构器时,编译器也会自动生成try/finally
    • 异步编程模型中异常会被“吞噬”然后重新抛出一样的异常
    • 编码建议,一般捕获并处理异常之后,不要把它吞噬,单独使用throw,抛出相同的异常
    • 关于异常的实践规范,可以好好思考一下,比如定义应用层异常、业务层异常、服务异常,通讯异常,然后将FCL的异常“吞噬”记录日志
    • dynamic对象调用方法如果失败,会抛出TargetInvocationException异常。最初抛出的异常会正常地在调用栈中向上传递。这是使用C#的dynamic基元类型代替反射的一个很好的理由。(如果使用反射来调用方法,方法内的异常不能被正常捕获)
    • 未捕获未处理的异常会写入Windows日志中
    • 分布式程序中,尽量少的暴露异常信息,如果堆栈信息暴露,可能服务器中的信息被泄露
    • 调试异常时,关注VS菜单“调试”-“异常”,可以强制引发某些异常发生,防止被“吞噬”(即使它被Catch)
    • 另外异常处理的性能影响,能避免就避免,比如,如果有Try前缀的方法,尽量使用Try前缀的方法(不过Try的方法依然可能会抛异常,比如style参数无效,会抛出ArgumentException,另外还有可能抛出OutMemoryException异常)
    • 如果要在抛出非预期的异常时维护状态,CER很有用。这种异常也称异步异常。CLR加载程序集时,在AppDomain的Load堆中创建一个类型对象,调用类型的静态构造器,并将IL代码JIT编译成本地代码。如果操作失败,CLR抛出异常报告失败。(很多隐式的非一致性的异常,导致无法预料)
    • CER, PrepareConstrainedRegions很特别的方法,JIT编译器如果发现一个try块前调用这个方法,会提前编译与try关联的catch和finally块中的代码。JIT编译器会加载任何程序集,创建任何类型对象,调用任何静态构造器,并对任何方法JIT编译。如果其中任何操作造成异常,这个异常会在线程进入try块之前发生。JIT编译器提前准备方法时,还会遍历调用图,前提时方法一个用了[ReliabilityContractAttribute]而且传递Consistency.WillNotCorruptState或Consistency.MayCorruptInstance枚举成员。这是由于加入方法会损坏AppDomain或进程状态,CLR便无法对状态一致性做出保证
    • 可以调用RuntimeHelper的PrepareMethod手动准备方法
    • CER文章参考:http://www.cnblogs.com/Ninputer/archive/2006/06/30/439757.html

    未捕获的异常处理

    • Winform, OnThreadException虚方法及Application的ThreadException事件
    • WPF程序Application的DispatcherUnhandledExceptions和System.WIndows.Therading.Dispatcher的UnhandledException和UnhandledExceptionFilter事件
    • 对于SIlverlight,System.Window.Application的UnhandledExceptoin事件
    • ASP.NET程序,System.Web.HttpApplication的Error事件
    • 对于WCF,System.ServiceModel.Dispatcher.ChnnelDispatche的ErrorHandlers属性

    契约式编程

    有时间我好好整理一下这方面的东西,毕竟一种编程习惯的培养,需要慢慢积累去逐渐使用新的思维

    参考文章:

    http://www.infoq.com/cn/news/2009/02/Code-Contracts-.NET

    http://www.cnblogs.com/lucifer1982/archive/2009/03/21/1418642.html

  • 相关阅读:
    I NEED A OFFER!
    水题 Codeforces Round #303 (Div. 2) A. Toy Cars
    模拟 HDOJ 5099 Comparison of Android versions
    模拟 HDOJ 5095 Linearization of the kernel functions in SVM
    贪心 HDOJ 5090 Game with Pearls
    Kruskal HDOJ 1863 畅通工程
    Kruskal HDOJ 1233 还是畅通工程
    并查集 HDOJ 1232 畅通工程
    DFS/并查集 Codeforces Round #286 (Div. 2) B
    水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta's Gift
  • 原文地址:https://www.cnblogs.com/fecktty2013/p/readingnotes-clr-exceptions.html
Copyright © 2011-2022 走看看