2011-12-30 23 views
23

Bazı Görevler oluşturan bir yöntem var ve geri dönmeden önce WaitAll ile onları bekliyorum. Sorun şu ki, bu görevler iptal edildiyse, o zaman WaitAll TaskCanceledException bir sürü içeren bir AggregateException atıyor. hakiki hata belirtmekTaskCanceledExceptions'ı atmadan nasıl görev bekleyebilirim?

  • İstisnalar: WaitAll iki farklı durumlarda istisnalar atmak anlamına gelir

    . Bunlar, nasıl ele alınacağını bilmediğimiz bir durum olduğu anlamına gelir; İşlemi sonunda sona erdirene kadar, işlenmemiş istisnalar olarak yayılmaları gerekir.

  • Kullanıcının bir İptal düğmesini tıkladığını gösteren istisnalar. Bu, görevin iptal edildiğini ve temizlendiğini ve programın normal şekilde çalışmaya devam etmesi gerektiği anlamına gelir. bu tamamen istisna olmayan durum atılmış bir istisna var, bu yüzden normal kontrol akışını sürdürmek için bunu yakalamak zorunda:

ikincisi dürüstçe bir vexing exception tanımına uyar. Neyse ki yakalamak kolay, değil mi? Sadece catch (AggregateException)'u ekleyin ve - oh bekleyin, bu ölümcül bir hata olduğunda atılan aynı türdür.

Döndükten sonra görevlerin çalışmayı bitirmesini beklemem gerekiyor (Artık veritabanı bağlantılarını, dosya tanıtıcılarını veya başka bir şeyi kullanmadıklarını bilmem gerekiyor), bu yüzden WaitAll veya başka bir şeye ihtiyacım var. benzer. Ve görevlerden herhangi biri hata yaptıysa, bu istisnaların işlenmeyen istisnalar olarak yayılmasını istiyorum. Sadece iptal için istisnalar istemiyorum.

İptal edilen görevler için WaitAll'u istisnalar atmasını nasıl engelleyebilirim?

+0

kullanın CancellationToken sürer aşırı gider. –

+0

@HansPassant, bu aşırı yüklenmeye ilişkin dokümanlar aslında belirtecini neyi kullandığını söylemiyor. Bu belirteçle ilişkili TaskCanceledExceptions'ı yoksayacak mı yoksa belirteci iptal edildiyse basitçe mi geri dönecek? Tüm görevler durdurulana kadar geri dönmemeye ihtiyacım var. –

+1

Görevleri iptal etmek için CancellationToken'i kullanırsınız. Ve şimdi elde edeceğiniz belirli OperationCancelException filtreleyin. –

cevap

28

AggregateException, bu durumlarda kullanılabilecek bir Handle yöntemi sağlar. Örneğin sen TaskCanceledException görmezden isterseniz yapabilirsiniz:

var all = new AggregateException(
    new NullReferenceException(), 
    new TaskCanceledException(), 
    new TaskCanceledException(), 
    new InvalidOperationException(), 
    new TaskCanceledException()); 

try 
{ 
    throw all; 
} 
catch (AggregateException errors) 
{ 
    errors.Handle(e => e is TaskCanceledException); 
} 

tüm istisnalar tip TaskCanceledException arasında ise, Handle yöntemi herhangi istisna olmayacaktır; aksi halde yalnızca işlenmeyen istisnaları içeren yeni bir AggregateException atılacaktır.

1

João Angelo's suggestion dayanarak, burada Görev sınıf uzantıyı

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace MySharedLibrary.Extensions 
{ 
    public static class TaskExtensions 
    { 

     // This code is based João Angelo's stackoverflow suggestion https://stackoverflow.com/a/8681687/378115 

     // Use this when a CancellationTokenSource is used 
     public static void SafeWait(this Task TargetTask, CancellationTokenSource TargetTaskCancellationTokenSource) 
     { 
      if (TargetTaskCancellationTokenSource.IsCancellationRequested == false) 
      { 
       TargetTaskCancellationTokenSource.Cancel(); 
      } 
      SafeWait(TargetTask); 
     } 

     // Use this when no CancellationTokenSource is used 
     public static void SafeWait(this Task TargetTask) 
     { 
      try 
      { 
       if (TargetTask.IsCanceled == false) 
       { 
        TargetTask.Wait(); 
       } 
      } 
      catch (AggregateException errors) 
      { 
       errors.Handle(e => e is TaskCanceledException); 
      } 
     } 

    } 
} 
İlgili konular