Secondo la tua domanda ...
Come passare i parametri al metodo Thread.ThreadStart () in C #?
... e l'errore che hai riscontrato, dovresti correggere il tuo codice
Thread thread = new Thread(new ThreadStart(download(filename));
per
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
Tuttavia, la domanda è più complessa come sembra all'inizio.
La Threadclasse attualmente (4.7.2) fornisce diversi costruttori e un Startmetodo con sovraccarichi.
Questi costruttori rilevanti per questa domanda sono:
public Thread(ThreadStart start);
e
public Thread(ParameterizedThreadStart start);
che può assumere un ThreadStartdelegato o un ParameterizedThreadStartdelegato.
I delegati corrispondenti si presentano così:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Come si può vedere, il costruttore corretto da usare sembra essere quello che prende un ParameterizedThreadStartdelegato in modo che un thread conforme alla firma specificata del delegato possa essere avviato dal thread.
Un semplice esempio per istanziare la Threadclasse sarebbe
Thread thread = new Thread(new ParameterizedThreadStart(Work));
o solo
Thread thread = new Thread(Work);
La firma del metodo corrispondente (chiamato Workin questo esempio) è simile alla seguente:
private void Work(object data)
{
...
}
Ciò che resta è iniziare il thread. Questo viene fatto usando uno dei due
public void Start();
o
public void Start(object parameter);
Mentre Start()avviare il thread e passare nullcome dati al metodo, Start(...)può essere utilizzato per passare qualsiasi cosa nel Workmetodo del thread.
Esiste tuttavia un grosso problema con questo approccio: tutto ciò che viene passato nel Workmetodo viene trasmesso in un oggetto. Ciò significa che all'interno del Workmetodo deve essere nuovamente eseguito il cast nel tipo originale come nell'esempio seguente:
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}");
}
Il casting è qualcosa che in genere non si desidera fare.
Cosa succede se qualcuno passa qualcos'altro che non è una stringa? Dal momento che questo non sembra possibile all'inizio (poiché è il mio metodo, so cosa faccio o Il metodo è privato, come dovrebbe mai qualcuno essere in grado di passargli qualcosa? ), Potresti finire con quel caso per vari motivi . Poiché alcuni casi potrebbero non essere un problema, altri lo sono. In questi casi probabilmente finirai con unInvalidCastException che probabilmente non noterai perché termina semplicemente il thread.
Come soluzione ti aspetteresti di ottenere un ParameterizedThreadStartdelegato generico come ParameterizedThreadStart<T>dove Tsarebbe il tipo di dati che vuoi passare al Workmetodo. Purtroppo qualcosa del genere non esiste (ancora?).
Esiste tuttavia una soluzione suggerita a questo problema. Implica la creazione di una classe che contenga sia i dati da passare al thread sia il metodo che rappresenta il metodo worker in questo modo:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Con questo approccio inizieresti il thread in questo modo:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Quindi in questo modo eviti semplicemente di lanciarti e hai un modo semplice di fornire dati a un thread ;-)