2011-11-14 15 views
54

ho il seguente codice:Passando un parametro di metodo che utilizza Task.Factory.StartNew

var task = Task.Factory.StartNew(CheckFiles, cancelCheckFile.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); 

private void CheckFiles() 
{ 
    //Do stuff 
} 

Ora voglio modificare CheckFiles ad accettare e intero e un riferimento BlockingCollection

private void CheckFiles(int InputID, BlockingCollection<string> BlockingDataCollection) 
{ 
    //Do stuff 
} 

posso' t sembra trovare un modo per iniziare questa attività come ho fatto sopra.

Potete essere d'aiuto?

Grazie

risposta

94

L'opzione migliore è probabilmente quella di utilizzare un'espressione lambda che si chiude sopra le variabili che si desidera visualizzare.

Tuttavia, fare attenzione in questo caso, soprattutto se si sta chiamando in un ciclo. (Dico questo perché la tua variabile è un "ID", e questo è comune in questa situazione.) Se chiudi la variabile con l'ambito sbagliato, puoi ottenere un bug. Per dettagli, vedere Eric Lippert's post on the subject. Ciò richiede in genere fare una temporanea:

foreach(int id in myIdsToCheck) 
{ 
    int tempId = id; // Make a temporary here! 
    Task.Factory.StartNew(() => CheckFiles(tempId, theBlockingCollection), 
     cancelCheckFile.Token, 
     TaskCreationOptions.LongRunning, 
     TaskScheduler.Default); 
} 

Inoltre, se il codice è come il precedente, si deve fare attenzione con l'utilizzo del LongRunning suggerimento - con lo scheduler di default, questo fa sì che ogni attività per ottenere il proprio thread dedicato invece di usare il ThreadPool. Se stai creando molte attività, è probabile che abbia un impatto negativo poiché non otterrai i vantaggi del ThreadPool. E 'tipicamente orientata per una singola, compito lungo in esecuzione (da cui il nome), non qualcosa che sarebbe stato implementato per lavorare su un elemento di una collezione, ecc

+0

Grazie. Li avvierò in un ciclo. Comunque ho bisogno di LongRunning. Il mio programma originale ha funzionato con un file, ma ora ha bisogno di fare del codice su numerosi file. Pertanto ho bisogno di passare l'ID, BlockingCollection, CancellationTokenSoure e StreamReader. Non ho aggiunto quei parametri di metodo aggiuntivi nella domanda tuttavia – Jon

+1

@Jon: Assicurati di controllare l'ambito di questi oggetti ... Ho appena menzionato l'hint LongRunning come qualcosa da tenere in considerazione - dirò che raramente è una buona idea utilizzare LongRunning, specialmente in .NET 4, se si stanno iniziando molte attività (ad esempio: lavorare in un ciclo), poiché il threadpool fornirà in genere un comportamento migliore. –

+0

Il ciclo è solo per iniziare le attività. Massimo di 4-6 – Jon

5

realizzazione del primo parametro come un esempio di Action, ad esempio

var inputID = 123; 
var col = new BlockingDataCollection(); 
var task = Task.Factory.StartNew(
    () => CheckFiles(inputID, col), 
    cancelCheckFile.Token, 
    TaskCreationOptions.LongRunning, 
    TaskScheduler.Default); 
17
class Program 
{ 
    static void Main(string[] args) 
    { 
     Task.Factory.StartNew(() => MyMethod("param value")); 
    } 

    private static void MyMethod(string p) 
    { 
     Console.WriteLine(p); 
    } 
} 
4

Per il superamento di un singolo intero Sono d'accordo con Reed Copsey di risposta. Se in futuro passerai a costanti più complicate, personalmente mi piacerebbe passare tutte le mie variabili come un tipo anonimo. Sarà simile a questa:

foreach(int id in myIdsToCheck) 
{ 
    Task.Factory.StartNew((Object obj) => 
     { 
      var data = (dynamic)obj; 
      CheckFiles(data.id, theBlockingCollection, 
       cancelCheckFile.Token, 
       TaskCreationOptions.LongRunning, 
       TaskScheduler.Default); 
     }, new { id = id }); // Parameter value 
} 

È possibile saperne di più nel mio blog

Problemi correlati