2013-06-28 2 views
6

У меня есть задача, которую я хочу отменить.Остановить задачу без ThrowIfCancellationRequested

Обычный способ для этого - CancellationToken.

this.task = new SpecialTask(() => 
{ 
    for (int i = 0; i < ushort.MaxValue; i++) 
    { 
     CancelToken.ThrowIfCancellationRequested(); 
     Console.WriteLine(i); 
    } 
}, this.CancelToken); 

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

this.task = new SpecialTask(() => 
{ 
    CancelToken.ThrowIfCancellationRequested(); 
    Operation1(); 

    CancelToken.ThrowIfCancellationRequested(); 
    Operation267(CancelToken); 

    CancelToken.ThrowIfCancellationRequested(); 
    object232.Operation345(); 

    CancelToken.ThrowIfCancellationRequested(); 
    object99.Operation44(CancelToken); 

    CancelToken.ThrowIfCancellationRequested(); 
    Operation5(CancelToken); 

    ... 

    CancelToken.ThrowIfCancellationRequested(); 
    Operation...n(CancelToken); 

}, this.CancelToken); 

Я использовал случайные числа для объектов и имен методов, чтобы показать, что ни один цикл не может быть создан вообще.

Что больше всего беспокоит то, что я должен продолжать писать то же самое CancelToken.ThrowIfCancellationRequested() снова и снова.

И, как будто этого недостаточно, я должен перетащить CancellationToken по всему моему коду, чтобы иметь возможность остановить длительную операцию - по словам Microsoft - в нужное время.

Сказав это, есть ли способ, которым я могу отказаться от этих повторяющихся звонков, которые отравляют мой код?

Мы также знаем, что при использовании

try 
{ 
    task.Wait(cancelToken); 
} 
catch(OperationCancelledException) 
{ 
} 

OperationCancelledException брошены и пойманный для метода Wait. Однако длительная операция, выполняемая заданием, не прекращается, если время от времени не выполняется никаких проверок CancelToken.ThrowIfCancellationRequested().

Можно ли остановить внутреннюю операцию, когда исключение поймано для ожидания?

+0

возможно дубликат [Асинхронный отмены C# TPL задачи] (http://stackoverflow.com/questions/17321692/asynchronously-abort-c-sharp-tpl-tasks) – dtb

+1

См. [Как отменить отмененные асинхронные операции?] (http://blogs.msdn.com/b/pfxteam/archive/2012/10/05/ how-do-i-cancel-non-cancelable-async-operations.aspx) Короче говоря, вы этого не делаете. Вам либо нужно это сделать, либо вообще не можете отменить задачу. Тем не менее, вы можете сделать несколько рефакторингов для этого кода, чтобы избежать некоторых повторений. – Servy

+0

Несмотря на то, что я понимаю необходимость обеспечения долговременной работы в нужное время, я бы надеялся, что структура на более низком уровне создаст встроенный механизм для отмены. Тем не менее, я посмотрю на ссылку, которую вы предоставили как можно скорее. Благодаря! – Paul

ответ

2

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

var actions = new List<Action>() 
{ 
    ()=>Operation1(), 
    ()=>Operation267(CancelToken), 
    ()=>object232.Operation345(), 
    //... 
}; 

foreach (var action in actions) 
{ 
    action(); 
    CancelToken.ThrowIfCancellationRequested(); 
} 
+0

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

+1

@Paul Вы все равно можете передать маркер отмены в методы и сделать то же самое в них, чтобы по-прежнему разрешать рефакторинг кода в методы. – Servy