C # try..catch - перенаправление потока обработки ошибок от одного перехвата к другому - PullRequest
5 голосов
/ 27 мая 2011

У меня есть блок try..catch, который выглядит следующим образом:

try
{
    ...
}
catch (IOException ioEx)
{
    ...
}
catch (Exception ex)
{
    ... 
}

Я бы хотел обработать только определенный тип IOException, а именно нарушение совместного доступа (Win32 0x20). Другие исключения IOException и все другие Exception потомки должны обрабатываться, как правило, вторым всеобъемлющим уловом.

Как только я узнаю, что IOException не является нарушением совместного использования, как я могу чисто перенаправить поток обработки ошибок на общий catch? Если я перебрасываю в catch (IOException), второй улов не вызывает. Я знаю, что я могу попробовать попробовать .. ловит, но есть ли более чистый способ?

РЕДАКТИРОВАТЬ: На логике обработчика факторинга

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

Прежде всего, предложение catch имеет прямой доступ ко всем локальным переменным до исключения. Но когда вы «передаете» обработку исключений другому методу, вы должны передать ему состояние. И когда вы меняете код, меняется и сигнатура метода-обработчика, что может быть проблемой сопровождения в более сложных сценариях.

Другая проблема заключается в том, что поток программы может быть скрыт. Например, если метод-обработчик в конечном итоге выбрасывает исключение, компилятор C # и анализаторы кода, такие как Resharper, не видят его:

    private void Foo()
    {
        string a = null;

        try
        {
            a = Path.GetDirectoryName(a);
            System.Diagnostics.Debug.Print(a);
        }
        catch (Exception ex)
        {                
            HandleException(ex, a); //Note that we have to pass the "a"
            System.Diagnostics.Debug.Print(
                "We never get here and it's not obvious" + 
                "until you read and understand HandleException"
            );
            ...!
        }
    }

    static void HandleException(Exception ex, string a)
    {
        if (a != null)
            System.Diagnostics.Debug.Print("[a] was not null");
        throw (ex); //Rethrow so that the application-level handler catches and logs it
    }

VS

    private void Bar()
    {
        string a = null;

        try
        {
            a = System.IO.Path.GetDirectoryName(a);
            System.Diagnostics.Debug.Print(a);
        }
        catch (Exception ex)
        {                
            if (a != null)
                System.Diagnostics.Debug.Print("[a] was not null");
            throw; //Rethrow so that the application-level handler catches and logs it
            System.Diagnostics.Debug.Print(
                "We never get here also, but now " + 
                "it's obvious and the compiler complains"
            );
            ...!
        }
    }

Если я хочу избежать подобных (незначительных) проблем, то, похоже, нет более чистого способа, чем вложение блоков try..catch, как указал Хэнк.

Ответы [ 6 ]

3 голосов
/ 27 мая 2011

Просто разделите логику обработки в отдельный метод.

try
{
    ...
}
catch (IOException ioEx)
{
    if (sharing violation)
       HandleSharingViolation();
    else 
       HandleNonsharingViolation();
}
catch (Exception ex)
{
       HandleNonsharingViolation();
}

Или протестируйте исключения самостоятельно

catch (Exception ex)
{
     if (ex is IOException && ex.IsSharingViolation()
       HandleSharingViolation();
     else
       HandleNonsharingViolation();
}
2 голосов
/ 27 мая 2011

Нет, тебе придется гнездиться.

Как только вы окажетесь в 1 из блоков захвата, эта попытка считается обработанной.

И я думаю, что это может иметь много смысла, «нарушение прав» звучит как особый случай, который, вероятно, не так тесно связан с остальными, как вы думаете. Если вы используете nest try-catch, должен ли блок try особого случая заключаться в точный тот же код? И, конечно, это кандидат на рефакторинг как отдельный метод.

0 голосов
/ 27 мая 2011

Попробуйте этот вложенный блок

try
{

}

catch (исключение ioex)
{
try
{

}
catch (Exception ex)
{

}
}

0 голосов
/ 27 мая 2011

как насчет "наконец-то"?

вы можете сначала установить 'переменную' в блоке IOException, как только вы узнаете, что IOException не передает нарушение.Затем, в вашем блоке finally, если эта «переменная» установлена, вы продолжаете делать все, что вам нужно.

Ниже импл.проверено и подтверждено.

        bool booleanValue = false;
        try
        {
            test1(); // this would thro IOException

        }
        catch (IOException e)
        {
            booleanValue = true; // whatever you need to do next
        }
        finally
        {
            if (booleanValue)
            {
                Console.WriteLine("Here");
            }
        }
0 голосов
/ 27 мая 2011

Использовать вложенные блоки try catch.

try
{
    try
    {
    }
    catch (IOException ioEx)
    {
        if (....)
        else
           throw;
    }
}
catch
{
}
0 голосов
/ 27 мая 2011

Создать метод для обработки исключения, передать исключение этому методу на основе типа Обрабатывать исключение так, как вы хотите. Вызовите этот метод в обоих этих блоках.

...