Видимо я не понял async/await
еще и следующий простой пример, уже вызывает некоторую головную боль:async/await - я использую неправильный контекст синхронизации?
Для тестирования я создать окно, которое представляет свой пользовательский интерфейс для теперь и я хочу сгореть асинхронный метод, который делает некоторую работу в фон при открытии окна. Я добавил Listview
в мое окно, чтобы проверить, отвечает ли пользовательский интерфейс.
Когда я выполнить следующий код, две вещи, которые я не понимаю:
- Мои
ListView
показываетCustomObjects
, что я определить в конструкторе. Поскольку я не мог использовать ключевое слово await в моем конструкторе, я ожидал, что вызовGetWebResponseAsync().ConfigureAwait(false)
заблокирует мой пользовательский интерфейс и создаст тупик (например, заменяет вызовGetWebResponseAsync().Wait()
). Кажется, чтоConfigureAwait(false)
уже делает мой метод запущенным в другом потоке, хотя я не запускал его как задачу или не ожидал его? - Пользовательский интерфейс отображается, но зависает при запуске метода
Async
. Это на самом деле не неожиданно, но меня смущает, если я рассматриваю предыдущее замечание о том, что Listview, по-видимому, доступен из кода, когда я выполняю свой метод async. Разве это не означает, что мой UI-поток НЕ заблокирован, и поэтому я должен иметь возможность взаимодействовать с пользовательским интерфейсом?
С тех пор как я застрял здесь, мне также хотелось бы знать, как я могу правильно вызвать мой метод асинхронного анализа в конструкторе сразу. Если я использую await GetWebResponseAsync().ConfigureAwait(false);
, он не компилируется, так как у моего конструктора нет ключевого слова async
. Однако я знаю, что я не должен использовать async void
(и даже если я попытаюсь сделать мой конструктор async void
, он не скомпилируется, потому что member names can not be the same as their enclosing type
).
public partial class TitleWindow : Window
{
public TitleWindow()
{
InitializeComponent();
// I can not use this because the constructor is not async.
//Task tempTask = await GetWebResponseAsync().ConfigureAwait(false);
GetWebResponseAsync().ConfigureAwait(false);
//This should in theory test if my UI-Thread is blocked?!
List<CustomObject> items = new List<CustomObject>();
items.Add(new CustomObject() { Title = "CustomTitle", Year = 2100});
items.Add(new CustomObject() { Title = "CustomTitle2", Year = 2015});
lvTitles.ItemsSource = items;
}
public async Task GetWebResponseAsync(){
WebRequest request = WebRequest.Create("http://www.google.com");
request.Credentials = CredentialCache.DefaultCredentials;
WebResponse response = await request.GetResponseAsync();
//Output for test purposes.
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = await reader.ReadToEndAsync();
Console.WriteLine(responseFromServer);
return;
}
}
Update:
Юваль Itzchakovs Ответ отлично работает для меня.
Также этот шаблон (взятый из ссылки в ответе Юваля Ицхакова) или комбинация обоих, похоже, способ пойти в более сложном сценарии. Это обеспечивает очень удобную возможность впоследствии убедиться, что асинхронный код из конструктора уже завершен, ожидая моего свойства инициализации.
public partial class TitleWindow : Window, IAsyncInitialization
{
public Task Initialization{get; private set;}
public TitleWindow()
{
InitializeComponent();
Initialization = GetWebResponseAsync();
}
public async Task GetWebResponseAsync(){
//unchanged
}
классный, это работает как шарм :) Думаю, я также понял ваши очень четкие объяснения. Спасибо! –
Да. Фактически он работал на вашем потоке пользовательского интерфейса. Вы можете проверить это, напечатав «ManagedThreadId» перед печатью ответа. Это происходит потому, что вы не используете 'ConfigureAwait (false)' внутри вашего метода веб-запроса. –
У меня есть еще один вопрос: ссылка, которую вы указали, имеет главу «Что НЕ делать» в самом конце. Не подключает мой асинхронный метод к событию загрузки, как вы предполагали, имеет те же недостатки, что и пример в этой главе статьи в блоге Стивена Клириса? В моем минималистическом примере ваше предложение работает отлично, конечно, так как мне не нужно знать, когда выполняется асинхронный метод, инициализирующий мой объект. Однако после прочтения сообщения в блоге я думаю, что я не должен использовать это вообще, если только я не предоставляю внутреннюю обработку ошибок и не может гарантировать, что объект уже правильно инициализирован? –