2011-08-11 63 views
6

我有一個短暫的異步任務,經常需要在啓動後取消。 「Task」類有一個IsCanceled指示器,我認爲它可以方便地用來指示異步任務被取消而不運行到完成,但是據我所知,唯一的方法是將異步任務標記爲取消在異步函數中拋出TaskCanceledException。常規拋出例外情況,以表明無意中出現的情況,違背了我應該如何理解例外情況。有沒有人知道一個更好的方式來表明一個異步任務被取消,當它預計會頻繁發生?C#async CTP - 如何將異步任務標記爲取消而不拋出TaskCanceledException?

我的下一個最佳選擇是返回擁有它自己的IsCanceled屬性的結構:

(我忽略了簡潔這裏一些好的編碼和風情習俗)

class MightBeCanceled<T> 
{ 
    public readonly T Value; 
    public readonly bool IsCanceled; 

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; } 
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true); 
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; } 
} 

... 

static async Task<MightBeCanceled<int>> Foo() 
{ 
    if (someCancellationCondition) 
     return MightBeCanceled<int>.Canceled; 
    else 
     return new MightBeCanceled<int>(42); 
} 

static async void Bar() 
{ 
    var mightBeCanceled = await Foo(); 

    if (mightBeCanceled.IsCanceled) 
     ; // Take canceled action 
    else 
     ; // Take normal action 
} 

但這似乎多餘且難以使用。更不用說它引入了一致性問題,因爲會有兩個IsCanceled(一個在Task中,一個在MightBeCanceled中)。

+1

誰取消Foo?它只能由調用者使用CancellationToken取消 –

回答

2

問題是,除非您選擇等待,否則將不會觀察到異常。因此,調用await的行爲意味着您最終會在返回最終值或您等待任務完成時的某個時刻觀察到異常。但是,如果你從不在意(這是一場火災和遺忘任務),那麼這個例外是一個非問題(大部分)。

我也是,發現這有點奇怪,總是必須嘗試/捕獲任務來處理聚合異常。但是,想一想:

try 
{ 
    var myResult = await Foo(); 

    // Do Success Actions Here... 
} 
catch(AggregateException e) 
{ 
    e.Flatten().Handle(ex => 
     { 
      if(ex is OperationCanceledException) 
      { 
       // Do Canceled Thing Here 
       return true; 
      } 

      return false; 
     }); 
} 

這不是太遙遠。在很多方面,我想取消另一項任務,我會怎麼做? ThreadAbortException?它看起來似乎並不那麼簡單地在取消時拋出特定的異常。

這幾乎是我在多個地方提倡的如何處理取消的模式。

2

通常,取消的目的是爲了使異步操作的調用者知道應該停止處理的操作。爲此,您將CancellationToken傳遞給異步方法。這就是爲什麼等待一個設置IsCancelled的任務會拋出它自己。這意味着對外部挑釁行爲的一個特殊信號。任務的取消不應該用於控制流程,但是隻有在等待方已經發出信號表明不再需要結果的情況下,才能爲異步操作提供儘早完成的選項。

如果異步操作在內部被取消,那麼您已經重載了這個概念,並且我會說那反映了取消差異的值是值得的,並且應該是結果容器上的屬性,類似於您提出的方式。但不是將其稱爲MightBeCancelled<T>,可能是類似InternallyCancellableResult<T>,以反映消除概念的差異。