none
4.0新异常机制下,IO异常应该怎么处理? RRS feed

  • 问题

  • 比方说我需要监听一个串口,或者socket,或者一个U盘里的或者相机里的文件, 我就是要等着Slave/Client/Guest/下位机发来的信号和数据. 可这是网线松了,串口被路过的碰掉了,U盘被拔出了,相机没电了,总之这个IO操作没法继续了, 异常, 而且是CSE.

    老机制下我捕获异常,改清理的清理,返回到未连接前的状态就好了. 可在新机制下, 推荐的处理泛型是怎么样的呢? 就让程序去死么? 不行呀,程序不能就这么挂掉,我得上帝,客户们老板们要求的, 必须要满足的.

    有别的兄弟也遇到这问题,有人回复说SerialPort应该现用现Close,就是Send完了赶紧Close掉. 不过个根本不是解决的办法嘛, 你通讯时间再短,也总会踩到雷的(恰好通讯中,插头就松了). 再说了,应用需要监听等待外设的信号呢?比如说某个工业用串口输入设备, 3D扫描仪什么的.

    总结一下问题,IO异常最常见,最基本不过了,新机制下是怎么处理的呀?

    • 已移动 Leo Liu - MSFT 2011年9月21日 6:56 Moved for better support. (发件人:Visual C#)
    2011年9月19日 15:23

答案

  • 这个问题的出现是因为理论上来讲,任何对 Finalizer 的调用都不应该抛出异常。4.0 里面对于 Non-CLR 的异常会直接被当成 Unhandled Exception 扔给 Application 或者 AppDomain,程序会直接崩溃 (默认行为下)。解决的思路只有两条,1、设法在调用处捕获该异常 (Win32 IO Exception);2、在 AppDomain 层面上捕获该异常。

    第一种思路可以试着将 catch (System.IO.IOException) 改成 catch () { }。这样会捕获所有的 CLR 以及非 CLR 异常。注意,catch () { } 和  catch (Exception) { } 是不等价的。

    第二种方法,设置全局的异常处理程序,如 WPF 中的 App.ThreadException,WinForm 中的 Application.UnhandledException 等。

    如果上面都无法解决问题,为了使程序不崩溃,可以考虑更改 UnhandledExceptionWrapMode。

    补充一点:这个问题您可以去报告到 Microsoft Connect,Finalizer 在任何时候被执行,都不期待抛出异常的。


    • 已编辑 mazhou 2011年9月20日 9:01
    • 已标记为答案 Paul Zhou 2011年9月27日 7:53
    2011年9月20日 8:59

全部回复

  • 补充一下, 直接调用flush什么的没事. 关键是FileStream在GC线程上调用终结器(析构)的时候,会遇到异常,这个是用新机制无法捕捉的.

       在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       在 System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
       在 System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
       在 System.IO.FileStream.Dispose(Boolean disposing)
       在 System.IO.FileStream.Finalize()

    2011年9月19日 15:50
  • 我知道可以给方法打Attribute或者改.config文件来配置成和之前版本一样的异常处理机制. 我是想知道,新机制下,处理这类问题的标准方法是什么呢? FileStream在GC调Finalize时遇到异常.
    2011年9月19日 15:55
  • 这个问题的出现是因为理论上来讲,任何对 Finalizer 的调用都不应该抛出异常。4.0 里面对于 Non-CLR 的异常会直接被当成 Unhandled Exception 扔给 Application 或者 AppDomain,程序会直接崩溃 (默认行为下)。解决的思路只有两条,1、设法在调用处捕获该异常 (Win32 IO Exception);2、在 AppDomain 层面上捕获该异常。

    第一种思路可以试着将 catch (System.IO.IOException) 改成 catch () { }。这样会捕获所有的 CLR 以及非 CLR 异常。注意,catch () { } 和  catch (Exception) { } 是不等价的。

    第二种方法,设置全局的异常处理程序,如 WPF 中的 App.ThreadException,WinForm 中的 Application.UnhandledException 等。

    如果上面都无法解决问题,为了使程序不崩溃,可以考虑更改 UnhandledExceptionWrapMode。

    补充一点:这个问题您可以去报告到 Microsoft Connect,Finalizer 在任何时候被执行,都不期待抛出异常的。


    • 已编辑 mazhou 2011年9月20日 9:01
    • 已标记为答案 Paul Zhou 2011年9月27日 7:53
    2011年9月20日 8:59