2015-08-10 5 views
7

Alcuni di noi preferiscono il codice in uno stile eccezionalmente leggero. Tuttavia, se si attende un'attività Task Library parallela e l'attività ha generato un'eccezione, verrà generata un'eccezione anche sul thread chiamante. Esiste un modo (preferibilmente standard) per evitare questo comportamento e basta controllare la risposta per le eccezioni al momento del ritiro?C'è un modo per aspettare un'attività TPL senza lanciare un'eccezione?

+0

Quindi in sostanza si sta chiedendo se qualche codice ha generato un'eccezione, esiste un modo per rilevarlo senza rilevarlo? –

+0

Sei assolutamente certo che devi * aspettare * per l'attività? Ti raccomanderei '.ContinueWith (...)' qualsiasi cosa tu abbia fatto dopo la chiamata Wait. –

+1

Questa è un'istanza in cui si dovrebbero utilizzare le continuazioni per interrogare lo stato dell'attività antecedente. La continuazione è fondamentale per TPL. Evitare di hackerare intorno a loro. Più precisamente, ingoiare le eccezioni è un odore di codice. – Gusdor

risposta

7

È possibile utilizzare Task.WaitAny come:

 var task = Task.Run(() => 
     { 
      // ... 
      throw new Exception("Blah"); 
     }); 
     Task.WaitAny(task); 
     if (task.IsFaulted) 
     { 
      var error = task.Exception; 
      // ... 
     } 
     else if (task.IsCanceled) 
     { 
      // ... 
     } 
     else 
     { 
      // Success 
     } 
2

In base a ciò che è stato scritto, è possibile rilevare l'eccezione e verificare la proprietà IsFaulted come soluzione? IsFaulted

+0

Sono andato con l'approccio Task.WaitAny. Per darti un contesto per il perché, il codice chiamato era codice di libreria che non potevo cambiare e veniva chiamato da fuori TPL, ma le eccezioni erano abbastanza comuni e, mentre dovevano essere gestite, c'era un sacco di rumore per affrontare se hai schiaffeggiato "pausa su eccezione", che faccio tutto il tempo. –

1

Cattura l'eccezione all'interno dell'attività e la restituisce nel risultato?

var task1 = Task.Factory.StartNew(() => 
{ 
    try 
    { 
     throw new MyCustomException("I'm bad, but not too bad!"); 
    } 
    catch(Exception ex) 
    { 
     return new Result { Error = ex }; 
    } 
}); 
3

Sfortunatamente, questa funzionalità non è integrata. Utilizzare questa soluzione alternativa:

myTask.ContinueWith(_ => { }, TaskCOntonuationOptions.ExecuteSynchronously).Wait(); 

È possibile effettuare questa operazione in un metodo di estensione.

+1

Puoi spiegare perché questa soluzione risolve il problema? – Gusdor

+1

@Gusdor cosa intendi? fa esattamente ciò che l'OP vuole. In attesa di un'attività senza generare un'eccezione. – boot4life

4

Non si può aspettare su un compito in errore senza sollevare un'eccezione. Ma si può aspettare una continuazione a tale compito, che completerà solo dopo che l'attività originale completato senza sollevare un'eccezione:

public static Task SwallowExceptions(this Task task) 
{ 
    return task.ContinueWith(_ => { }); 
} 

faultedTask.SwallowExceptions().Wait(); 
if (faultedTask.IsFaulted) 
{ 
    // handle exception 
} 

Se il vostro compito restituisce un valore, si può rappresentare che nel metodo estensioni e ritorno il valore effettivo se non c'erano eccezioni o il valore predefinito se c'erano:

public static Task<T> SwallowExceptions<T>(this Task<T> task) 
{ 
    return task.ContinueWith(completedTask => 
     completedTask.IsFaulted 
      ? default(T) 
      : completedTask.Result); 
}