Асинхронный вызов в синхронном методе - PullRequest
6 голосов
/ 21 октября 2011

Вот простой пример:

public event EventHandler CookinDone = delegate{};

public void CoockinRequest(){
    var indicator = new ActivityIndicator();
    ActivityIndicator.Show("Oooo coockin' something cool");

    var bw = new BackgroundWorker();    
    bw.DoWork += (sender, e) => CockinService.Cook();
    bw.RunWorkerCompleted += (sender, e) => {
       indicator.Hide();
       CookinDone.Invoke(this,null);
    };

    bw.RunWorkerAsync();
}

Теперь, каждый раз, когда я использую этот метод, мне приходится перехватывать событие CookinDone и двигаться дальше.

var cook = new Cook();
cook.CookinDone += (sender, e) => MessageBox.Show("Yay, smells good");
cook.CoockinRequest();

Но как мне это упростить?сделав возвращаемый тип метода как Boolean и вернув результат после завершения Cookin?

if (CoockinRequest()) MessageBox.Show('Yay, smells even better');

если я добавлю туда что-то вроде while (bw.IsBusy), это повредит мой ActivityIndicator, заморозит основной поток, и я чувствую, что это будетбыть самой отвратительной вещью.Есть также некоторые вещи Monitor.Wait и некоторые другие, такие как TaskFactory, но все эти вещи кажутся слишком сложными для использования в простых сценариях.

Он может также отличаться в разных средах, например, какой-то подход хорош для приложений WPF, другой - для чего-то другого и так далее, но должен быть общий шаблон, не так ли?

Как вы это делаете, ребята?

1 Ответ

7 голосов
/ 21 октября 2011

Нет прямого способа сделать это в .NET 4. Это на самом деле очень соответствует новой функциональности async / await, появившейся в следующей версии C #.

Параллельная библиотека задач может использоваться в .NET 4 для достижения этой цели сегодня. Вы могли бы сделать это, изменив свой код так, чтобы он возвращал Task<bool>, чтобы вызывающий мог ожидать его (при необходимости) или подписать продолжение на задачу, которая будет выполняться после ее завершения. *

Для этого вам нужно переписать приведенный выше код следующим образом:

public Task<bool> CoockinRequestAsync()
{
    var indicator = new ActivityIndicator();
    ActivityIndicator.Show("Oooo coockin' something cool");

    // This assumes Cook() returns bool...
    var task = Task.Factory.StartNew(CockinService.Cook);

    // Handle your removal of the indicator here....
    task.ContinueWith( (t) => 
       {
           indicator.Hide();
       }, TaskScheduler.FromCurrentSynchronizationContext());

    // Return the task so the caller can schedule their own completions
    return task;
}

Затем, когда вы будете использовать это, вы напишите что-то вроде:

private void SomeMethod()
{
    var request = this.CoockinRequestAsync();

    request.ContinueWith( t =>
    {
        // This will run when the request completes... 
        bool result = t.Result;

        // Use result as needed here, ie: update your UI

    }, TaskScheduler.FromCurrentSynchronizationContext());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...