Как определить HResult для исключения System.IO.IOException? - PullRequest
34 голосов
/ 14 июня 2009

Свойство 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 . Будет ли это возвращать uint как 0x80070021?

Ответы [ 5 ]

55 голосов
/ 14 июня 2009

Для .Net Framework 4.5 и выше вы можете использовать свойство Exception.HResult:

int hr = ex.HResult;

Для более старых версий вы можете использовать Marshal.GetHRForException, чтобы вернуть HResult, но этот имеет значительные побочные эффекты и не рекомендуется :

int hr = Marshal.GetHRForException(ex);
11 голосов
/ 03 мая 2013

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

3 голосов
/ 19 ноября 2015

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

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

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

0 голосов
/ 14 июня 2009

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

...