2013-09-07 3 views
11

Учитывая токен отмены, я хотел бы создать из него ожидаемую задачу, которая никогда не будет полной, но может быть отменена. Мне это нужно для шаблона, как это, что ИМО должна быть довольно распространенным явлением:Задача от токена отмены?

async Task DoStuff(Task t, CancellationToken ct) 
{ 
    // t was made from TaskCompletionSource, 
    // both t and ct are beyond my control 

    Task t2 = TaskFromCancellationToken(ct); 
    await Task.WhenAny(t, t2); 

    // do stuff 
} 

Лучшая идея у меня до сих пор это:

Task TaskFromCancelationToken(CancellationToken ct) 
{ 
    return Task.Delay(Timeout.Infinite, ct); 
} 

Есть ли лучший способ сделать это логика случается?

+0

Пересмотр этого, .NET 4.6 имеет ['Task.FromCanceled'] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.fromcanceled (v = vs.110) .aspx). – Noseratio

ответ

17

Это не чрезвычайно общий, но достаточно распространен, чтобы быть частью моей библиотеки AsyncEx. Я использую something like это:

public static Task AsTask(this CancellationToken cancellationToken) 
{ 
    var tcs = new TaskCompletionSource<object>(); 
    cancellationToken.Register(() => tcs.TrySetCanceled(), 
     useSynchronizationContext: false); 
    return tcs.Task; 
} 
+0

Но ['cancelationToken.Register'] (https://msdn.microsoft.com/en-us/library/dd321635 (v = vs.110) .aspx) возвращает [' CancellationTokenRegistration'] (https: // msdn. microsoft.com/en-us/library/system.threading.cancellationtokenregistration(v=vs.110).aspx), который вы никогда не распоряжаетесь (он реализует 'IDisposable'). Разве это не проблема? – Paya

+0

@Paya: Да. Текущая версия AsyncEx представляет метод ['ToCancellationTokenTaskSource'] (https://github.com/StephenCleary/AsyncEx/blob/master/Source/Nito.AsyncEx%20 (NET45% 2C% 20Win8% 2C% 20WP8% 2C% 20WPA81) /CancellationTokenExtensions.cs#L28), который рекомендуется вместо 'AsTask'. [Следующая версия полностью удаляет «AsTask») (https://github.com/StephenCleary/AsyncEx.Tasks/blob/master/src/Nito.AsyncEx.Tasks/CancellationTokenTaskSource.cs). –

+0

Есть ли какая-то причина предпочитать, что над предложенным 'Task.Delay'? Это похоже на очень элегантное решение и не связано с раздражением «IDisposable». – Paya

0
Task.Delay(Timeout.Infinite, cancellationToken) 

Ответ вы предлагаете в вашем вопросе является лучшим решением для моих знаний. Вот почему:

  • Безопасно
  • Очень маленький кусочек кода требуется
  • Стандартная библиотека

Task.Delay подход активно используется много людей, как мне известно, и также рекомендуется в блогах Microsoft. MSDN Example.

Зачем писать код (включая тесты) самостоятельно, используя TaskCompletionSource для преобразования токена отмены в задачу? Предпочтительно использовать стандартные библиотеки вместо того, чтобы изобретать колесо; они, скорее всего, будут без ошибок, чем ваш код.

+0

С .NET 4.6 Я использую ['Task.FromCanceledTask'] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.fromcanceled (v = vs.110) .aspx). – Noseratio

Смежные вопросы