web-dev-qa-db-de.com

Wie übergebe ich Parameter an die ThreadStart-Methode in Thread?

Wie übergebe ich Parameter an die Thread.ThreadStart() Methode in C #?

Angenommen, ich habe eine Methode namens 'download'

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

Jetzt habe ich einen Thread in der Hauptmethode erstellt:

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

fehlermethodentyp erwartet.

Wie kann ich mit der Zielmethode mit Parametern Parameter an ThreadStart übergeben?

273
Swapnil Gupta

Das einfachste ist nur

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

Der Vorteil (gegenüber ParameterizedThreadStart) besteht darin, dass Sie mehrere Parameter übergeben können und die Kompilierungszeit überprüfen können, ohne die ganze Zeit von object aus konvertieren zu müssen.

664
Marc Gravell

Schauen Sie sich dieses Beispiel an:

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

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

Sie erstellen zuerst einen Thread, indem Sie die Delegate-Methode an die Worker-Methode übergeben, und starten ihn dann mit einer Thread.Start-Methode, die Ihr Objekt als Parameter verwendet.

In deinem Fall solltest du es also so benutzen:

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

Ihre 'download'-Methode muss jedoch weiterhin Objekt und nicht Zeichenfolge als Parameter verwenden. Sie können es in einen String in Ihrem Methodentext umwandeln.

34
ŁukaszW.pl

Sie möchten den Delegaten ParameterizedThreadStart für Thread-Methoden verwenden, die Parameter annehmen. (Oder überhaupt nicht, und lassen Sie den Konstruktor Thread schließen.)

Anwendungsbeispiel:

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

thread.Start(filename)
23
Noldorin

Sie könnten auch delegate so mögen ...

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

Sie können die Thread-Funktion (Download) und die erforderlichen Parameter (Dateinamen) in einer Klasse einkapseln und den ThreadStart-Delegaten verwenden, um die Thread-Funktion auszuführen.

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

In Additional

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

Wie wäre es damit: (oder ist es in Ordnung, so zu verwenden?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
    try
    {
        //Staff to do
        Console.WriteLine(test);
    }
    catch (Exception ex)
    {
        throw;
    }
})).Start();

Nach Ihrer Frage ...

Wie übergebe ich Parameter an die Thread.ThreadStart () - Methode in C #?

... und dem aufgetretenen Fehler müssten Sie Ihren Code ab korrigieren

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

zu

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



Die Frage ist jedoch komplexer, als es zunächst scheint.

Die Klasse Thread enthält derzeit (4.7.2) mehrere Konstruktoren und eine Start -Methode mit Überladungen.

Diese relevanten Konstruktoren für diese Frage sind:

public Thread(ThreadStart start);

und

public Thread(ParameterizedThreadStart start);

die entweder einen ThreadStart Delegierten oder einen ParameterizedThreadStart Delegierten aufnehmen.

Die entsprechenden Delegierten sehen folgendermaßen aus:

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

Wie zu sehen ist, scheint der richtige Konstruktor derjenige zu sein, der einen ParameterizedThreadStart -Delegaten entgegennimmt, so dass eine Methode, die der angegebenen Signatur des Delegaten entspricht, vom Thread gestartet werden kann.

Ein einfaches Beispiel für die Instanziierung der Klasse Thread wäre

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

oder nur

Thread thread = new Thread(Work);

Die Signatur der entsprechenden Methode (in diesem Beispiel Work genannt) sieht folgendermaßen aus:

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

Was bleibt ist, den Thread zu starten. Dies geschieht entweder mit

public void Start();

oder

public void Start(object parameter);

Während Start() den Thread starten und null als Daten an die Methode übergeben würde, kann Start(...) verwendet werden, um alles an die Methode zu übergeben Work Methode des Threads.

Es gibt jedoch ein großes Problem bei diesem Ansatz: Alles, was an die Work -Methode übergeben wird, wird in ein Objekt umgewandelt. Das bedeutet, dass innerhalb der Work -Methode erneut auf den ursprünglichen Typ umgewandelt werden muss, wie im folgenden Beispiel gezeigt:

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



Casting ist etwas, das Sie normalerweise nicht möchten.

Was ist, wenn jemand etwas anderes übergibt, das keine Schnur ist? Da dies zunächst nicht möglich zu sein scheint (weil Es ist meine Methode, ich weiß was ich tue oder Die Methode ist privat, wie sollte jemand jemals in der Lage sein, etwas an sie weiterzugeben? ) Möglicherweise haben Sie aus verschiedenen Gründen genau diesen Fall. Da einige Fälle möglicherweise kein Problem darstellen, sind es andere. In solchen Fällen erhalten Sie wahrscheinlich ein InvalidCastException , das Sie wahrscheinlich nicht bemerken werden, weil es den Thread einfach beendet.

Als Lösung würden Sie einen generischen ParameterizedThreadStart -Delegaten wie ParameterizedThreadStart<T> Erwarten, wobei T der Datentyp ist, den Sie an die Work -Methode übergeben möchten . Leider existiert so etwas (noch?) Nicht.

Es gibt jedoch ein Lösungsvorschlag für dieses Problem. Es wird eine Klasse erstellt, die sowohl die an den Thread zu übergebenden Daten als auch die Methode enthält, die die Worker-Methode wie folgt darstellt:

public class ThreadWithState
{
    private string message;

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

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

Mit diesem Ansatz würden Sie den Thread wie folgt starten:

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

thread.Start();

Auf diese Weise vermeiden Sie einfach das Herumwerfen und haben eine typsichere Möglichkeit, Daten für einen Thread bereitzustellen ;-)

0
Markus Safar