#c_sharp #net #async_await
Вызываю метод, который при искл.чение перебрасывает его наверх, чтобы обработать во внешнем коде private async void FillCurrentWeather(string place) { XmlSerializer serializer = new XmlSerializer(typeof(Current)); string xml = await GetWeather(CurrentWeatherUrl,place,7); if (xml != null) { try { TextReader reader = new StringReader(xml); Current forecast = (Current)serializer.Deserialize(reader); PlaceName.Content = forecast.City.Name + "," + forecast.City.Country; CurrentWeather.Update(forecast); reader.Dispose(); } catch (InvalidOperationException ex) { throw new InvalidOperationException(ex.Message, ex.InnerException); } } } Внешний код try { FillCurrentWeather(place); FillDayWeather(place); FillWeekWeather(place); } catch (InvalidOperationException ex) { MessageBox.Show("Ошибка при обработке данных внешнего сервиса\n" + ex.Message); } Но исключение не обрабатываеися и выскакивает в отладчике. В чем может быть причина?
Ответы
Ответ 1
Во время выполнения под отладчиком выпадают все исключения, отмеченные в списке Debug -> Windows -> Exception Settings (Ctrl+Alt+E). Это нормально. Если вы продолжите выполнение программы (F5), то дальше отработают ваши catch блоки. UPD С добавление полного кода стала понятна настоящая причина, к которой предыдущий абзац не имеет никакого отношения. Проблема в этом: async void FillCurrentWeather Для полного понимания того, как работает async/await, отсылаю к видео. Здесь же вкратце опишу, что происходит при выполнении программы. Итак: В блоке try внешнего кода вызывается метод FillCurrentWeather(place);. Выполнение метода FillCurrentWeather доходит до этой строки и покидает его*: string xml = await GetWeather(CurrentWeatherUrl,place,7); В блоке try внешнего кода отрабатывают все остальные методы. Метод GetWeather завершает выполнение, продолжается выполнение метода FillCurrentWeather, вываливается исключение. НО! Блок try/catch во внешнем коде уже завершился, он не может поймать это исключение! Поэтому исключение вываливается на самом верхнем уровне как необработанное (UnhandledTaskException). async void опасны именно по этим причинам: мы не знаем, когда они на самом деле завершаются соответственно мы не может адекватно реагировать на исключения в таких методах async void сигнатуру можно использовать только для событий и методов, имеющих событийную семантику, плюс не забывать целиком оборачивать все тело таких методов в try/catch, поскольку если возникнет исключение, вы либо получите необработанное исключение (если возникло в UI потоке), либо, в случае если оно возникло в потоке пула, вы об этом или не узнаете, или это исключение убьет процесс (в случае с .NET 4.0 будет именно так). Какие у вас варианты решения? В данном случае -- только один: изменить сигнатуру метода на async Task и ожидать завершения этого метода во внешнем коде. И еще маленький совет: в вашем случае блок try/catch в методе FillCurrentWeather вообще не нужен, поэтому что он по сути ничего не делает. Просто уберите его. (А впредь, если хотите пробрасывать исключения, оборачивая их в другие, всегда включайте исключение целиком, а не его InnerException, которого может и не быть: throw new Exception("This is new exception", e)). *на самом деле это упрощение, и выполнение продолжится вглубь до того момента, когда вызов уйдет к IO-устройству. Важно лишь, что программа не дожидается завершения этого метода. UPD2 Чтобы не терять параллелизацию получения данных о погоде, которая невольно достигалась при использовании async void методов, нужно использовать Task.WhenAll: try { var currentTask = FillCurrentWeather(place); var dayTask = FillDayWeather(place); var weekTask = FillWeekWeather(place); await Task.WhenAll(currentTask, dayTask, weekTask); } catch (InvalidOperationException ex) { MessageBox.Show("Ошибка при обработке данных внешнего сервиса\n" + ex.Message); }
Комментариев нет:
Отправить комментарий