Как я могу продолжить выполнение блока catch, когда пользователь вводит учетные данные, из исключения, вызванного всплывающим окном для учетных данных? - PullRequest
0 голосов
/ 30 марта 2011

Я создал приложение Winforms, которое обращается к папкам на другом сервере (в другом домене активной директории). Строка получает все каталоги из папки, но иногда может произойти сбой, за исключением того, что учетные данные для доступа к папке (базовая проверка подлинности) не были сохранены, поэтому диалоговое окно базовой проверки подлинности снова и снова всплывает, нарушая работу системы.

В соответствующем блоке catch, как я могу справиться с этим, возобновив выполнение блока catch после того, как пользователь введет свои учетные данные, а затем повторите соответствующий код?

Спасибо

1 Ответ

1 голос
/ 30 марта 2011

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

Еслиповторная попытка должна продолжаться с точки исключения, тогда, вероятно, лучше всего поместить этот шаг в цикл, например:

private const int maxRetryAttempts = 3;

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while (true)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             if (remainingAttemtps <= 0)
                 throw;
             remainingAttempts--;             
             MessageBox.Show(ex.Message);
        }
    }
}

Причина в то время как (true)

Оператор while(true){...} может показаться немного странным, но в этом случае это необходимо.Как представляется, это не бесконечный цикл, поскольку метод либо возвращает значение, либо выдает исключение в течение указанного числа итераций.

Обычно можно ожидать цикл с непостоянным управлениемвыражение.

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)  //  Non-constant expression.
    {
        ...
    }
}  //  Compile error - Not all code paths return a value.

Это не было сделано в этом методе, чтобы удовлетворить детектор достижимости компилятора.Компилятор увидит константу true в операторе while и узнает, что оператор через некоторое время недостижим, и, следовательно, конец метода недостижим.Если бы была выбрана не константа, то после цикла необходимо было бы разместить код, чтобы либо вернуть значение, либо выдать исключение.Давайте рассмотрим каждый из вариантов.

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    return null;
}  

Мы могли бы вернуть нулевое значение (или какой-либо другой индикатор ошибки), и в этом случае вызывающий код должен ожидать нулевые значения и обрабатывать их.Это показалось мне неуклюжим дизайном.Я бы скорее гарантировал, что, если метод вернется, он вернёт хорошее значение.

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    throw new UnauthroizedAccessException();  // This exception does not contain any good debugging data.
}  

Другая альтернатива - вызвать исключение в конце метода.Это разумный вариант, но не идеальный.Если мы создадим новое исключение, то оно почти наверняка будет менее значимым, чем то, которое изначально вызвало проблему, которая уже была обнаружена и отброшена.

Предположим, что мы сохранили исходное исключение.

private static MyData ReadDataFile(string path)
{
    UnauthorizedAccessException exception = null;
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             exception = ex;
             MessageBox.Show(ex.Message);
        }
    }
    throw exception;  // The StackTrace gets replaced to indicate this line of code.
}

Мы можем перебросить исключение, которое мы перехватили, создав переменную Exception в верхней части метода и сохранив в нем перехваченное исключение.Проблема в том, что это приведет к замене трассировки стека и усложнит отладку приложения в будущем.Лучше просто позволить исключению распространяться без изменений, используя throw;, чтобы перебросить исходное исключение (которое может произойти только в блоке catch, но не в конце метода.

Так что из всехдоступные альтернативы, я оценил while(true) как лучший вариант, потому что он гарантирует, что контроль оставит этот метод либо с хорошими данными, либо с нетронутым исключением.

Обратите внимание, что если метод не имеет возвращаемого значения (void), тогда проблемы достижимости исчезают, но не логические проблемы. Нам все равно придется решать вопрос о выходе из метода, не выполнив то, что должен был сделать.

private static void ReadDataFile(string path)
{
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             MessageBox.Show(ex.Message);
        }
    }
    //  Compiles justs fine, but did we actually read the data file? 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...