Метод StartSomething()
не имеет смысла для меня. Он запускает новый Task
, а затем просто синхронно ожидает результат (.Result
) этой задачи, который практически бесполезен - он почти [*] такой же, как звонить DoSomething()
напрямую. Также DoSomething()
уже асинхронный, поэтому вам не нужно начинать новый Task
для него.
Похоже, вам не нужен StartSomething()
метод вообще. Если вы сделаете Button_Click
обработчик async
, вы можете просто await DoSomething()
напрямую:
private TaskCompletionSource<bool> TaskCompletion = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
bool k = await DoSomething();
}
private async Task<bool> DoSomething()
{
TaskCompletion = new TaskCompletionSource<bool>();
await Task.WhenAny(TaskCompletion.Task, Task.Delay(3000));
MessageBox.Show("DoSomething");
return true;
}
1020 *
*
Edit:
При использовании асинхронного решения до конца (как показано выше) IMO является предпочтительным способом, если вы действительно не можете изменить код вызова на async
, я могу придумать два способа вызова async
метод из синхронного метода без блокировки пользовательского интерфейса. Во-первых, вручную настроить задачи продолжения, например:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoSomething().ContinueWith((task) =>
{
bool k = task.Result;
// use the result
},
// TaskScheduler argument is needed only if the continuation task
// must run on the UI thread (eg. because it access UI elements).
// Otherwise this argument can be omitted.
TaskScheduler.FromCurrentSynchronizationContext());
// Method can exit before DoSomething().Result becomes
// available, which keep UI responsive
}
Таким образом, вы в основном разделяете синхронный метод (одно разбиение вместо каждого await
) на несколько частей (лямбда-методы продолжения), связанных .ContinueWith
. Это похоже на то, что await
делает под капотом. Проблема в том, что в отличие от await
(который производит хороший и чистый код), ваш код будет заполнен этими лямбдами продолжения. И будет намного хуже, когда вы добавите блоки обработки исключений, using
блоки и т. Д.
Второй подход - использование вложенных циклов, например. Метод расширения Стивена Туба * WaitWithNestedMessageLoop :
static T WaitWithNestedMessageLoop<T>(this Task<T> task)
{
var nested = new DispatcherFrame();
task.ContinueWith(_ => nested.Continue = false, TaskScheduler.Default);
Dispatcher.PushFrame(nested);
return task.Result;
}
Вложенные циклы - довольно продвинутая техника (я на самом деле никогда не использовал ее), и я не рекомендую использовать ее, если не нужно.
<Ч />
[*] Существуют различия в обработке исключений, выполнении потоков и т. Д., Но они не имеют отношения к этому вопросу.