Как определить HResult для System.IO.IOException?

Свойство System.Exception.HResult защищено. Как я могу заглянуть внутрь исключения и получить HResult, не прибегая к размышлениям или другим уродливым хакам?


Здесь ситуация:
Я хочу написать средство резервного копирования, которое открывает и читает файлы в системе. Я открываю файл с FileAccess.Read и FileShare.ReadWrite, в соответствии с этим руководством, потому что мне все равно, открыт ли файл для записи в то время, когда я читал Это.

В некоторых случаях, когда файл, который я читаю, открывается другим приложением, метод System.IO.FileStream.Read() генерирует исключение System.IO.IOException: "Процесс не может получить доступ к файлу, потому что другой процесс заблокирован часть файла". Это ошибка 33, или я думаю, что HResult 0x80070021. [ EDIT: Я считаю, что это может быть возвращено, когда другой процесс вызывает LockFileEx, чтобы заблокировать диапазон байтов в файле. ]

Я хочу сделать паузу и повторить попытку, когда я получу эту ошибку. Я думаю, что это подходящее действие для этого. Если процесс блокировки быстро освобождает блокировку байтового диапазона, я могу продолжить чтение файла.

Как я могу отличить IOException по этой причине от других? Я могу думать об этих путях:

  • частное отражение - не хочу этого делать. Перф воняет.
  • вызовите Exception.ToString() и проанализируйте строку. Чувствует себя взломанным. Не будет работать в версиях i18n.

Мне не нравятся эти параметры. Нет ли лучшего, более чистого пути?


Я просто обыскал и нашел System.Runtime.InteropServices.Marshal.GetHRForException. Будет ли это возвращать uint как 0x80070021?

Ответ 2

Для того, что стоит, System.Exception.HResult больше не защищается в .NET 4.5 - защищен только сеттер. Это не помогает с кодом, который может быть скомпилирован с несколькими версиями фреймворка.

Ответ 3

Вы также можете использовать интерфейс 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");
    }
}

Ответ 4

Помогает ли помощь CanRead в этом случае?
т.е. вызов CanRead, если это возвращает true, вызовите Read()

Ответ 5

Профилировали ли вы один из этих случаев? Я бы предположил, что метод отражения не так уж и медленный, особенно по отношению ко всем другим работам, которые будет выполняться вашим приложением, и как часто это исключение будет происходить.

Если это окажется узким местом, вы можете изучить кэширование некоторых операций отражения или генерировать динамический IL для извлечения этого свойства.