Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: CheesoОтветов: 6

Свойство 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?

  • ›Личное отражение - не хочу этого делать. Перф будет вонять. - Exception perf все равно воняет, так что я бы не стал беспокоиться о производительности. Однако для отражения требуется FullTrust, он уродлив, не поддерживается и подвержен поломкам - вот почему вам не следует этого делать. Mark Brackett 08.08.2009

exceptionhresult

Ответы

Ответ 1 · рейтинг 58 · JaredPar

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

int hr = ex.HResult;

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

int hr = Marshal.GetHRForException(ex);

Ответ 2 · рейтинг 11 · UweBaemayr

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

Ответ 3 · рейтинг 5 · Maxence

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

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

Ответ 5 · Kevin Pullin

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

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

Ответ 6 · Stefan Steiger

Некромантинг.
Или вы можете просто получить защищенное свойство с помощью отражения:

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;
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы