2013-06-28 13 views
6

Ho un'attività che desidero annullare.Interrompere un'operazione senza ThrowIfCancellationRequested

Il metodo normale per farlo è con CancellationToken.

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

Tuttavia, nel mondo reale le cose non sono mai così semplici. Il nostro codice asincrono non può essere avvolto e sembra che questo:

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); 

ho usato numeri casuali per gli oggetti e nomi di metodo per dimostrare che nessun ciclo può essere creato qualunque.

Ciò che più preoccupa è che devo continuare a scrivere lo stesso CancelToken.ThrowIfCancellationRequested() più e più volte.

E, come se non bastasse, devo trascinare lo CancellationToken su tutto il mio codice solo per poter interrompere l'operazione di lunga durata - secondo Microsoft - al momento giusto.

Detto questo, c'è un modo per dispensare queste chiamate ripetitive che avvelenano il mio codice?

sappiamo anche che, quando si utilizza

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

un OperationCancelledException è gettato e catturato per il metodo Wait. Tuttavia, l'operazione lunga eseguita dall'attività non si interrompe se non ci sono controlli di volta in volta CancelToken.ThrowIfCancellationRequested().

C'è un modo per interrompere l'operazione interna quando l'eccezione viene catturata per l'attesa?

+0

possibile duplicato del [asincrono abortire C Tasks # TPL] (http://stackoverflow.com/questions/17321692/asincrono-abort-c-sharp-tpl-tasks) – dtb

+1

Vedere [Come annullare le operazioni asincrone non cancellabili?] (http://blogs.msdn.com/b/pfxteam/archive/2012/10/05/ how-do-i-cancel-non-cancellable-async-operations.aspx) In breve, non è così. O devi farlo o non puoi assolutamente cancellare l'attività. Detto questo, potresti fare alcuni refactoring su questo codice per evitare alcune delle ripetizioni. – Servy

+0

Mentre capisco la necessità di assicurarsi che l'operazione di lunga durata venga interrotta al momento giusto, avrei sperato che il framework avesse, a un livello inferiore, un meccanismo integrato per cancellarlo piacevolmente. Cercherò il collegamento che hai fornito il prima possibile, però. Grazie! – Paul

risposta

2

È possibile refactoring del codice in un ciclo per evitare la cancellazione ripetitiva tra ogni riga:

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

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

Questo mi richiederebbe di immaginare una grana molto più fine per la separazione del mio codice in metodi. Invece di avere 3 buoni metodi solidi, sono quasi costretto a dividere in metodi molto più piccoli solo in modo che la cancellazione venga rilevata abbastanza presto. Eliminare un codice sorgente da un posto e aggiungerne un altro da qualche altra parte non lo fa – Paul

+1

@Paul È ancora possibile passare il token di cancellazione nei metodi e fare la stessa cosa in quelli, per consentire comunque il codice di refactoring in metodi. – Servy