繁体   English   中英

如何确定 System.IO.IOException 的 HResult?

[英]How do I determine the HResult for a System.IO.IOException?

System.Exception.HResult 属性受到保护。 如何在不诉诸反射或其他丑陋黑客的情况下窥视异常并获得 HResult?


这是情况:
我想编写一个备份工具,它可以打开和读取系统上的文件。 我根据本指南使用 FileAccess.Read 和 FileShare.ReadWrite 打开文件,因为我不关心文件在我阅读时是否打开以进行写入。

在某些情况下,当我正在读取的文件被另一个应用程序打开时,System.IO.FileStream.Read() 方法会抛出 System.IO.IOException,“该进程无法访问该文件,因为另一个进程已锁定的一部分文件”。 这是错误 33 ,或者我认为 HResult 0x80070021。 [编辑:我相信当另一个进程调用LockFileEx以锁定文件中的字节范围时,可以返回此值。]

当我收到此错误时,我想暂停并重试。 我认为这是在这里采取的适当行动。 如果锁定过程快速释放字节范围锁定,那么我可以继续读取文件。

出于这个原因,我如何将 IOException 与其他异常区分开来? 我可以想到这些方法:

  • 私人反思 - 不想那样做。 Perf 会发臭。
  • 调用 Exception.ToString() 并解析字符串。 感觉很鸡肋。 不适用于 i18n 版本。

我不喜欢这些选项。 没有更好、更清洁的方法吗?


我只是四处搜索,发现System.Runtime.InteropServices.Marshal.GetHRForException 那会返回一个像 0x80070021 这样的 uint 吗?

对于 .Net Framework 4.5 及更高版本,您可以使用Exception.HResult属性:

int hr = ex.HResult;

对于旧版本,您可以使用Marshal.GetHRForException来取回 HResult,但这具有显着的副作用,不建议使用

int hr = Marshal.GetHRForException(ex);

就其价值而言, System.Exception.HResult在 .NET 4.5 中不再受保护——只有 setter 受到保护。 这对可能使用多个版本的框架编译的代码没有帮助。

您还可以使用ISerializable接口:

static class IOExceptionExtensions
{
    public static int GetHResult(this IOException ex)
    {
        var info = new SerializationInfo(typeof (IOException), new FormatterConverter());
        ex.GetObjectData(info, new StreamingContext());
        return info.GetInt32("HResult");
    }
}

死灵法术。
或者您可以通过反射获取受保护的属性:

private static int GetHresult(System.Exception exception)
{
    int retValue = -666;

    try
    {
        System.Reflection.PropertyInfo piHR = typeof(System.Exception).GetProperty("HResult", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);

        if (piHR != null)
        {
            object o = piHR.GetValue(exception, null);
            retValue = System.Convert.ToInt32(o);
        }
    }
    catch (Exception ex)
    {
    }

    return retValue;
}

CanRead属性在这种情况下有帮助吗?
即调用CanRead ,如果返回 true,调用Read()

你有没有分析过这些案例中的任何一个? 我想反射方法并不是那么慢,特别是相对于您的应用程序将要执行的所有其他工作以及此异常可能发生的频率。

如果事实证明这是一个瓶颈,您可以考虑缓存一些反射操作或生成动态 IL 来检索属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM