如何确定 System.IO.IOException 的 HResult?
System.Exception.HResult 属性受到保护。 如何在不诉诸反射或其他丑陋黑客的情况下查看异常内部并获取 HResult?
情况如下:
我想编写一个备份工具,它可以打开并读取系统上的文件。 我使用 FileAccess.Read 和 FileShare.ReadWrite 打开文件,根据 此指南,因为我不关心文件在读取时是否打开用于写入。
在某些情况下,当我正在读取的文件被另一个应用程序打开时,System.IO.FileStream.Read() 方法会抛出 System.IO.IOException,“该进程无法访问该文件,因为另一个进程已锁定该文件的一部分”文件”。 这是错误33,或者我认为HResult 0x80070021。 [编辑:我相信当另一个进程调用 LockFileEx 锁定文件内的字节范围。]
当我收到此错误时,我想暂停并重试。 我认为这是在这里采取的适当行动。 如果锁定过程快速释放字节范围锁定,那么我可以继续读取文件。
我怎样才能将这个原因的 IOException 与其他原因区分开来? 我可以想到这些方法:
- 私下反思——不想那样做。 性能会发臭。
- 调用 Exception.ToString() 并解析字符串。 感觉很哈克。 不适用于 i18n 版本。
我不喜欢这些选项。 难道没有更好、更干净的方法吗?
我刚刚四处搜索,发现 System.Runtime.InteropServices .Marshal.GetHRForException。 会返回像 0x80070021 这样的 uint 吗?
The System.Exception.HResult property is protected. How can I peek inside an exception and get the HResult without resorting to reflection or other ugly hacks?
Here's the situation:
I want to write a backup tool, which opens and reads files on a system.
I open the file with FileAccess.Read and FileShare.ReadWrite, according to this guidance, because I don't care if the file is open for writing at the time I read it.
In some cases, when a file I am reading is open by another app, the System.IO.FileStream.Read() method throws a System.IO.IOException, "The process cannot access the file because another process has locked a portion of the file". This is error 33, or I think HResult 0x80070021. [EDIT: I believe this can be returned when another process calls LockFileEx to lock a byte range within a file.]
I'd like to pause and retry when I get this error. I think this is the appropriate action to take here. If the locking process releases the byte-range lock quickly, then I can proceed reading the file.
How can I distinguish an IOException for this reason, from others? I can think of these ways:
- private reflection - don't wanna do that. Perf will stink.
- call Exception.ToString() and parse the string. Feels hacky. Won't work in i18n versions.
I don't like these options. Isn't there a better, cleaner way?
I just searched around and found System.Runtime.InteropServices.Marshal.GetHRForException. Will that return a uint like 0x80070021?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
对于 .Net Framework 4.5 及更高版本,您可以使用 Exception.HResult 属性:
对于旧版本,您可以使用
Marshal.GetHRForException
来获取 HResult,但是这个 具有显着的副作用并且不推荐:For .Net Framework 4.5 and above, you can use the
Exception.HResult
property:For older versions, you can use
Marshal.GetHRForException
to get back the HResult, but this has significant side-effects and is not recommended:无论如何,System.Exception.HResult 在 .NET 4.5 中不再受到保护——只有 setter 受到保护。 这对于可能使用多个版本的框架编译的代码没有帮助。
For what it's worth, System.Exception.HResult is no longer protected in .NET 4.5 -- only the setter is protected. That doesn't help with code that might be compiled with more than one version of the framework.
您还可以使用
ISerialized
接口:You can also use the
ISerializable
interface:CanRead
属性在这种情况下有帮助吗?即调用
CanRead
,如果返回 true,则调用Read()
Does
CanRead
property help in this case?i.e. call
CanRead
, if that returns true, callRead()
您是否对这些案例进行了分析? 我想反射方法并不是那么慢,特别是相对于您的应用程序将要执行的所有其他工作以及此异常可能发生的频率而言。
如果它被证明是一个瓶颈,您可以考虑缓存一些反射操作或生成动态 IL 来检索属性。
Have you profiled either of these cases? I'd imagine that the reflection method isn't all that slow, especially relative to all the other works your app will be doing and how often this exception will be likely to occur.
If it turns out to be a bottleneck you can look into caching some of the reflection operations or generate dynamic IL to retrieve the property.
死灵术。
或者您可以通过反射获取受保护的属性:
Necromancing.
Or you can just fetch the protected property by reflection: