73 votes

Passage d'un paramètre de méthode à l'aide de Task.Factory.StartNew

J'ai le code suivant :

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

private void CheckFiles()
{
  //Do stuff
}

Je veux maintenant modifier CheckFiles pour qu'il accepte un nombre entier et une référence à BlockingCollection.

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

Je n'arrive pas à trouver un moyen de démarrer cette tâche comme je l'ai fait ci-dessus.

Pouvez-vous nous aider ?

Gracias

118voto

Reed Copsey Points 315315

La meilleure option est probablement d'utiliser une expression lambda qui se ferme sur les variables que vous voulez afficher.

Cependant, faites attention dans ce cas, surtout si vous l'appelez dans une boucle. (Je le mentionne car votre variable est un "ID", et c'est courant dans cette situation). Si vous fermez sur la variable dans la mauvaise portée, vous pouvez obtenir un bug. Pour plus de détails, voir Le billet d'Eric Lippert sur le sujet . Cela nécessite généralement la création d'un poste temporaire :

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

De plus, si votre code est comme celui qui précède, vous devez faire attention à l'utilisation de la fonction LongRunning Conseil : avec l'ordonnanceur par défaut, chaque tâche obtient son propre thread dédié au lieu d'utiliser le ThreadPool. Si vous créez de nombreuses tâches, cela aura probablement un impact négatif car vous ne bénéficierez pas des avantages du ThreadPool. Il est généralement destiné à une tâche unique et longue (d'où son nom), et non à quelque chose qui serait mis en œuvre pour travailler sur un élément d'une collection, etc.

25voto

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => MyMethod("param value"));
    }

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

10voto

paulselles Points 55

Pour le passage d'un seul entier, je suis d'accord avec la réponse de Reed Copsey. Si, à l'avenir, vous avez l'intention de passer des constuctions plus compliquées, j'aime personnellement passer toutes mes variables sous la forme d'un type anonyme. Cela ressemble à quelque chose comme ceci :

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
}

Vous pouvez en apprendre davantage à ce sujet dans mon blog

6voto

Adam Ralph Points 15420

Construire le premier paramètre comme une instance de Action par exemple

var inputID = 123;
var col = new BlockingDataCollection();
var task = Task.Factory.StartNew(
    () => CheckFiles(inputID, col),
    cancelCheckFile.Token,
    TaskCreationOptions.LongRunning,
    TaskScheduler.Default);

1voto

user3761555 Points 405

Essayez ça,

        var arg = new { i = 123, j = 456 };
        var task = new TaskFactory().StartNew(new Func<dynamic, int>((argument) =>
        {
            dynamic x = argument.i * argument.j;
            return x;
        }), arg, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
        task.Wait();
        var result = task.Result;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X