积极答复者
4.0新异常机制下,IO异常应该怎么处理?

问题
-
比方说我需要监听一个串口,或者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#)
答案
-
这个问题的出现是因为理论上来讲,任何对 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 在任何时候被执行,都不期待抛出异常的。
全部回复
-
补充一下, 直接调用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() -
这个问题的出现是因为理论上来讲,任何对 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 在任何时候被执行,都不期待抛出异常的。