Страницы

Поиск по вопросам

воскресенье, 14 апреля 2019 г.

Цикл внутри try…catch, как написать красивый код?

Код примерно следующий:
public void AntigateAuthorize(int appId, string email, string password, Settings settings, string antigateKey) { var authorizationCompleted = false;
try { Authorize(appId, email, password, settings); authorizationCompleted = true; } catch (CaptchaNeededException exception) { var captchaSid = exception.Sid; var image = GetImageFromUrl(exception.Img.AbsoluteUri);
try { const int numberOfAuthorizationRetries = 5; var retryAuthorizationsCount = numberOfAuthorizationRetries; do { var anticaptcha = new AntiCaptcha(antigateKey); try { var captchaKey = anticaptcha?.GetAnswer(image);
if (captchaKey != null) { Authorize(appId, email, password, settings, captchaSid, captchaKey); authorizationCompleted = true; } else { Logger.Error("Ответ от сервера Antigate не получен."); } } catch (CaptchaNeededException) { Logger.Trace("Капча распознана неверно."); anticaptcha.FalseCaptcha(); retryAuthorizationsCount--; if (retryAuthorizationsCount == 0) { Logger.Trace("Заданное количество попыток авторизации исчерпано."); throw; } } } while (!authorizationCompleted && retryAuthorizationsCount > 0); } catch (AntigateErrorException aee) { Logger.Error("Ошибка Antigate: {0}", aee.Message); } } catch (VkApiAuthorizationException) { Logger.Error("Не удалось авторизовать приложение. Неправильный логин или пароль."); } catch (VkApiException) { Logger.Error("В процессе попытки авторизации произошла неизвестная ошибка."); } }
public static Image GetImageFromUrl(string url) { using (var stream = ((HttpWebResponse)((HttpWebRequest)WebRequest.Create(url)).GetResponse()).GetResponseStream()) return stream == null ? null : Image.FromStream(stream); }
Проблема в том, если обрабатывать ошибку CaptchaNeededException однократно, то всё получается, а если в цикле - получается плохо и некрасиво.


Ответ

Можно попробовать разбить на мелкие функции. Например, так:
public void AntigateAuthorize( int appId, string email, string password, Settings settings, string antigateKey) { try { try { Authorize(appId, email, password, settings); } catch (CaptchaNeededException exception) { AuthorizeWithCaptcha(appId, email, password, settings, exception); } } catch (AntigateErrorException) { // ? } catch (VkApiAuthorizationException) { Logger.Error( "Не удалось авторизовать приложение. Неправильный логин или пароль."); } catch (VkApiException) { Logger.Error( "В процессе попытки авторизации произошла неизвестная ошибка."); } }
Вспомогательные функции:
private void AuthorizeWithCaptchaOnceImpl( int appId, string email, string password, Settings settings, CaptchaNeededException reason, AntiCaptcha anticaptcha) { var captchaSid = reason.Sid; var image = GetImageFromUrl(reason.Img.AbsoluteUri);
try { var captchaKey = anticaptcha.GetAnswer(image);
if (captchaKey == null) { Logger.Error("Ответ от сервера Antigate не получен."); throw new NoAntigateResponceException(); }
Authorize(appId, email, password, settings, captchaSid, captchaKey); } catch (CaptchaNeededException) { Logger.Trace("Капча распознана неверно."); anticaptcha.FalseCaptcha(); throw; } }
void AuthorizeWithCaptcha( int appId, string email, string password, Settings settings, CaptchaNeededException exception) { try { var anticaptcha = new AntiCaptcha(antigateKey); const int numberOfAuthorizationRetries = 5;
CaptchaNeededException currentException = exception;
for (int retry = 0; retry < numberOfAuthorizationRetries; retry++) { try { AuthorizeWithCaptchaOnceImpl( appId, email, password, settings, currentException, anticaptcha); return; } catch (CaptchaNeededException ex) { currentException = ex; } catch (NoAntigateResponceException ex) { // nothing to do, just retry } } throw new RetryNumberExceededException(); } catch (AntigateErrorException aee) { Logger.Error("Ошибка Antigate: {0}", aee.Message); throw; } }
Заметьте, что я немного поменял логику. Например, после неудачного распознавания капчи теперь картинка меняется. Также, в результате превышения разрешённого количества попыток распознавания выбрасывается исключение (хотя, возможно, вы захотите вернуть bool из функции).

Комментариев нет:

Отправить комментарий