Как мне запланировать условное продолжение? - PullRequest
11 голосов
/ 24 октября 2011

У меня есть некоторый графический интерфейс для нескольких запросов LINQ.Выполнение запросов занимает некоторое время, поэтому я хотел бы, чтобы графический интерфейс реагировал и отображал индикаторы занятости и индикаторы выполнения.Многие запросы должны проверять определенные условия, существующие в данных.Если запрос возвращает пустой результат, приложение должно продолжить выполнение следующего запроса.Если он возвращает результат, возвращаемый набор будет иметь серьезность «предупреждения» или «ошибки».Если это предупреждения, исполнение должно продолжаться.Если это ошибки, он должен остановиться.

Большая часть кода играет в "пинг-понг" с пулом потоков и графическим интерфейсом.Квази-код:

TaskFactory.StartNew(()=>
    {
       Run in background
    }.ContinueInGui(()=>
    {
       Update something
    }).ContinueInBackground(()=>
    {
      Do more work;
    }).ContinueInGui(()=> etc etc

Это аккуратно и красиво.Тем не менее, я не вижу, как я могу вставить условия, чтобы идти по другим маршрутам продолжения или разорвать цепочку продолжения, если в данных обнаружены ошибки.

Не существует метода для ContinueWithIf ( предикат , делегат {}, TaskScheduler) Я использую TaskCancellation, я выбрасываю исключение?Или есть какой-то простой механизм ветвления, о котором я не думаю?

Ответы [ 2 ]

9 голосов
/ 25 октября 2011

Хороший вариант здесь - использовать CancelationTokenSource и просто пометить его как отмененный, если вы хотите «разорвать» цепочку продолжения. Включив TaskContinuationOptions.NotOnCanceled в ContinueWith для последующих задач, вы можете запретить их планирование в любой момент, отметив CancelationTokenSource как отмененный.

Если вы действительно хотите использовать предикат, вместо настройки продолжения в основном методе, вам нужно создать собственный метод, чтобы справиться с этим для вас. Это может быть сделано с помощью метода расширения, который присоединяет продолжение - это продолжение может проверить предикат и при необходимости запустить продолжение. Это будет выглядеть примерно так:

public static Task ContinueWithIf(this Task task, Func<bool> predicate, Action<Task> continuation, TaskScheduler scheduler)
{
    var tcs = new TaskCompletionSource<object>(); 

    task.ContinueWith( t =>
    {
        if (predicate())
        {
            new TaskFactory(scheduler).StartNew( 
                () => 
                {
                    continuation(task); 
                    tcs.SetResult(null); 
                });
        }
        else
        {
            tcs.TrySetCanceled();
        }
    });

    return tcs.Task;
}

Конечно, вы, вероятно, захотите сделать версию для Task<T> дополнительно, а также обработать состояния сбоя / отмены в Задаче. При этом он должен работать правильно.

4 голосов
/ 24 октября 2011

Если есть ошибок , вам следует соответствующим образом ошибиться.Затем вы можете использовать TaskContinuationOptions.OnlyOnRanToCompletion и т. Д. В вызове ContinueWith.

В основном есть три возможных состояния в конце жизни задания:

  • RanToCompletion
  • Отменено
  • Ошибка

Вы можете ContinueWith применить к любой разумной комбинации этих статусов, и вы можете прикрепить различные продолжения к одной и той же родительской задачеесли вы хотите делать разные вещи, основанные на ошибке, успехе, отмене и т. д.

...