web-dev-qa-db-fra.com

Comment passer des paramètres à la méthode ThreadStart dans Thread?

Comment passer des paramètres à la méthode Thread.ThreadStart() en C #?

Supposons que j'ai une méthode appelée 'télécharger'

public void download(string filename)
{
    // download code
}

Maintenant, j'ai créé un thread dans la méthode principale:

Thread thread = new Thread(new ThreadStart(download(filename));

type de méthode d'erreur attendu.

Comment puis-je passer des paramètres à ThreadStart avec une méthode cible avec des paramètres?

273
Swapnil Gupta

Le plus simple est juste

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

L'avantage de ceci (par rapport à ParameterizedThreadStart) est que vous pouvez transmettre plusieurs paramètres et que vous obtenez une vérification au moment de la compilation sans avoir à transtyper à partir de object tout le temps.

664
Marc Gravell

Regardez cet exemple:

public void RunWorker()
{
    Thread newThread = new Thread(WorkerMethod);
    newThread.Start(new Parameter());
}

public void WorkerMethod(object parameterObj)
{
    var parameter = (Parameter)parameterObj;
    // do your job!
}

Vous créez d'abord un thread en transmettant délégué à une méthode de travail, puis vous le démarrez avec une méthode Thread.Start qui prend votre objet en tant que paramètre.

Donc, dans votre cas, vous devriez l'utiliser comme ceci:

    Thread thread = new Thread(download);
    thread.Start(filename);

Mais votre méthode de "téléchargement" doit toujours prendre objet, pas chaîne en tant que paramètre. Vous pouvez le convertir en chaîne dans le corps de votre méthode.

34
ŁukaszW.pl

Vous souhaitez utiliser le délégué ParameterizedThreadStart pour les méthodes de thread qui prennent des paramètres. (Ou aucun, en fait, et laissez le constructeur Thread en déduire.)

Exemple d'utilisation:

var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent

thread.Start(filename)
23
Noldorin

Vous pourriez aussi delegate comme si ...

ThreadStart ts = delegate
{
      bool moreWork = DoWork("param1", "param2", "param3");
      if (moreWork) 
      {
          DoMoreWork("param1", "param2");
      }
};
new Thread(ts).Start();
5
Master Mick

Vous pouvez encapsuler la fonction de thread (téléchargement) et le (s) paramètre (s) requis (nom de fichier) dans une classe et utiliser le délégué ThreadStart pour exécuter la fonction de thread.

public class Download
{
    string _filename;

    Download(string filename)
    {
       _filename = filename;
    }

    public void download(string filename)
    {
       //download code
    }
}

Download = new Download(filename);
Thread thread = new Thread(new ThreadStart(Download.download);
2
Jackypengyu

De plus

    Thread thread = new Thread(delegate() { download(i); });
    thread.Start();
2
Metin Atalay

Que diriez-vous de ceci: (ou est-ce que ça peut être utilisé comme ça?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
    try
    {
        //Staff to do
        Console.WriteLine(test);
    }
    catch (Exception ex)
    {
        throw;
    }
})).Start();
0
Cansın Şenalioğlu

Selon ta question ...

Comment passer des paramètres à la méthode Thread.ThreadStart () en C #?

... et l'erreur que vous avez rencontrée, vous devrez corriger votre code depuis

Thread thread = new Thread(new ThreadStart(download(filename));

à

Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);



Cependant, la question est plus complexe qu'il n'y paraît au premier abord.

La classe Thread (4.7.2) fournit actuellement plusieurs constructeurs et une méthode Start avec surcharges.

Ces constructeurs pertinents pour cette question sont:

public Thread(ThreadStart start);

et

public Thread(ParameterizedThreadStart start);

qui soit prend un ThreadStart délégué ou un ParameterizedThreadStart .

Les délégués correspondants ressemblent à ceci:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

Donc, comme on peut le constater, le constructeur approprié à utiliser semble être celui prenant un délégué ParameterizedThreadStart de sorte qu'une méthode conforme à la signature spécifiée du délégué puisse être lancée par le thread.

Un exemple simple d'instanciation de la classe Thread serait

Thread thread = new Thread(new ParameterizedThreadStart(Work));

ou juste

Thread thread = new Thread(Work);

La signature de la méthode correspondante (appelée Work dans cet exemple) ressemble à ceci:

private void Work(object data)
{
   ...
}

Ce qui reste est de commencer le fil. Ceci est fait en utilisant soit

public void Start();

ou

public void Start(object parameter);

Tandis que Start() démarrerait le thread et transmettrait null en tant que données à la méthode, Start(...) peut être utilisé pour passer n'importe quoi dans la méthode Work du thread.

Il existe toutefois un gros problème avec cette approche: tout ce qui est passé dans la méthode Work est converti en un objet. Cela signifie que dans la méthode Work, il doit être converti dans le type d'origine à nouveau, comme dans l'exemple suivant:

public static void Main(string[] args)
{
    Thread thread = new Thread(Work);

    thread.Start("I've got some text");
    Console.ReadLine();
}

private static void Work(object data)
{
    string message = (string)data; // Wow, this is ugly

    Console.WriteLine($"I, the thread write: {message}");
}



Le casting est une chose que vous ne voulez généralement pas faire.

Et si quelqu'un passe quelque chose d'autre qui n'est pas une chaîne? Comme cela semble impossible au début (parce que c'est ma méthode, je sais ce que je fais ou . La méthode est privée. Comment quelqu'un devrait-il pouvoir ), vous pouvez éventuellement vous retrouver exactement dans cette affaire pour diverses raisons. Comme certains cas peuvent ne pas être un problème, d'autres le sont. Dans de tels cas, vous obtiendrez probablement un InvalidCastException que vous ne remarquerez probablement pas, car il met simplement fin au fil.

En tant que solution, vous devriez vous attendre à obtenir un délégué générique ParameterizedThreadStart tel que ParameterizedThreadStart<T>T serait le type de données que vous souhaitez transmettre à la méthode Work. Malheureusement, quelque chose comme ça n'existe pas (encore?).

Il existe cependant une solution suggérée à cette question. Cela implique la création d'une classe qui contient à la fois les données à transmettre au thread et la méthode qui représente la méthode de travail de la manière suivante:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

Avec cette approche, vous commenceriez le fil comme ceci:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

Donc, de cette façon, vous évitez simplement de lancer des discussions et vous avez un moyen sûr de fournir des données à un thread ;-)

0
Markus Safar