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

C# 如何确定System.IO.IOException的HResult?,c#,.net,exception,hresult,C#,.net,Exception,Hresult,System.Exception.HResult属性受保护。我如何才能窥视异常内部并获得HResult,而不诉诸反射或其他丑陋的黑客 情况如下: 我想写一个备份工具,可以打开和读取系统上的文件。 根据,我使用FileAccess.Read和FileShare.ReadWrite打开文件,因为我不在乎在读取文件时文件是否已打开进行写入 在某些情况下,当另一个应用程序打开我正在读取的文件时,System.IO.FileStream.Read()方法会引发System.IO.IOException,

System.Exception.HResult属性受保护。我如何才能窥视异常内部并获得HResult,而不诉诸反射或其他丑陋的黑客


情况如下:
我想写一个备份工具,可以打开和读取系统上的文件。 根据,我使用FileAccess.Read和FileShare.ReadWrite打开文件,因为我不在乎在读取文件时文件是否已打开进行写入

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

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

我如何才能将基于此原因的IOException与其他IOException区分开来?我可以想出以下方法:

  • 私人反思-我不想那样做。表演会发臭的
  • 调用Exception.ToString()并分析字符串。感觉有点不舒服。在i18n版本中不起作用
我不喜欢这些选择。难道没有更好更干净的方法吗



我只是到处找了找,找到了。这会返回类似0x80070021的uint吗?在这种情况下,
是否可以读取属性帮助?

i、 e.调用
CanRead
,如果返回true,则调用
Read()

您分析过这两种情况吗?我可以想象,反射方法并没有那么慢,特别是相对于你的应用程序将要做的所有其他工作,以及这种异常可能发生的频率


如果结果是瓶颈,您可以研究缓存某些反射操作或生成动态IL来检索属性。

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

int hr = ex.HResult;
对于较旧的版本,可以使用返回HResult,但是:


值得一提的是,System.Exception.HResult在.NET4.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是真的。我相信80070021是一个暂时的错误。如果我正确地读取了文档,建议的做法是“等待一段时间,然后重试”。是否可能是您打开了该文件进行读取&其他人也打开了该文件(使用FileShare.Read),第一个调用方无法再读取?这就是您所说的瞬态吗?不,我的意思是,另一个进程对文件调用了FileLock或FileLockEx(),以锁定文件中的某个范围。这有时称为字节范围锁。在某个时刻,锁定过程将释放范围锁定。这就是我所说的“暂时”的意思。谢谢你。来自VB的背景,我认为文件可以被一个阅读器完全锁定。从未想过可以锁定一系列字符进行阅读。>私人反思-不想这样做。性能会发臭异常性能很糟糕,所以我不会担心性能方面的问题。然而,反射确实需要完全信任,是丑陋的,不受支持的,容易被破坏,这就是为什么你不应该这样做。非常感谢!在C#/COM互操作性的情况下,这确实可以简化开发。+1 Eww需要完全信任。。。但这仍然是一个解决方案。请注意副作用:“请注意GetHRForException方法设置了当前线程的IErrorInfo。这可能会导致ThroweExceptionForHR方法等方法出现意外结果,如果设置了,这些方法默认使用当前线程的IErrorInfo。”我强烈建议您不要使用GetHRForException。这引起了一个非常奇怪的问题,我们花了几个月才明白:
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;
}