Zgodnie z twoim pytaniem ...
Jak przekazać parametry do metody Thread.ThreadStart () w C #?
... i napotkany błąd, musisz poprawić swój kod
Thread thread = new Thread(new ThreadStart(download(filename));
do
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
Pytanie to jest jednak bardziej złożone, jak się wydaje na początku.
Obecnie Thread
klasa (4.7.2) udostępnia kilka konstruktorów i Start
metodę z przeciążeniami.
Tymi odpowiednimi konstruktorami tego pytania są:
public Thread(ThreadStart start);
i
public Thread(ParameterizedThreadStart start);
które biorą ThreadStart
delegata lub ParameterizedThreadStart
delegata.
Odpowiedni delegaci wyglądają tak:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Jak można zauważyć, poprawnym konstruktorem do użycia wydaje się być ten, który bierze ParameterizedThreadStart
delegata, aby pewna metoda zgodna z określoną sygnaturą delegata mogła zostać uruchomiona przez wątek.
Prostym przykładem Thread
byłoby zainicjowanie klasy
Thread thread = new Thread(new ParameterizedThreadStart(Work));
Lub tylko
Thread thread = new Thread(Work);
Podpis odpowiedniej metody (wywołanej Work
w tym przykładzie) wygląda następująco:
private void Work(object data)
{
...
}
Pozostało rozpocząć wątek. Odbywa się to za pomocą jednego z nich
public void Start();
lub
public void Start(object parameter);
Chociaż Start()
uruchamia wątek i przekazuje null
dane do metody, Start(...)
może służyć do przekazywania wszystkiego do Work
metody wątku.
Jest jednak jeden duży problem z tym podejściem: wszystko przekazane do Work
metody jest rzutowane na obiekt. Oznacza to, że w ramach Work
metody należy ponownie rzutować na oryginalny typ, jak w poniższym przykładzie:
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}");
}
Przesyłanie jest czymś, czego zwykle nie chcesz robić.
Co się stanie, jeśli ktoś przekaże coś innego, co nie jest łańcuchem? Ponieważ na początku wydaje się to niemożliwe (ponieważ jest to moja metoda, wiem, co robię lub metoda ta jest prywatna, w jaki sposób ktoś powinien być w stanie przekazać coś do niej? ), Być może z tego powodu możesz skończyć dokładnie z tą sprawą . Ponieważ niektóre przypadki mogą nie stanowić problemu, inne tak. W takich przypadkach prawdopodobnie skończysz z InvalidCastException
czymś, czego prawdopodobnie nie zauważysz, ponieważ po prostu kończy wątek.
Jako rozwiązanie można oczekiwać ogólnego ParameterizedThreadStart
delegata, na przykład, ParameterizedThreadStart<T>
gdzie T
byłby typ danych, które chcesz przekazać do Work
metody. Niestety coś takiego jeszcze nie istnieje (jeszcze?).
Istnieje jednak sugerowane rozwiązanie tego problemu. Polega ona na utworzeniu klasy, która zawiera zarówno dane, które mają być przekazywane do wątku, jak i metodę reprezentującą metodę roboczą w następujący sposób:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Przy takim podejściu zaczynasz wątek w następujący sposób:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
W ten sposób po prostu unikniesz przerzucania się i masz bezpieczny sposób dostarczania danych do wątku ;-)