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 Threadklasa (4.7.2) udostępnia kilka konstruktorów i Startmetodę z przeciążeniami.
Tymi odpowiednimi konstruktorami tego pytania są:
public Thread(ThreadStart start);
i
public Thread(ParameterizedThreadStart start);
które biorą ThreadStartdelegata lub ParameterizedThreadStartdelegata.
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 ParameterizedThreadStartdelegata, aby pewna metoda zgodna z określoną sygnaturą delegata mogła zostać uruchomiona przez wątek.
Prostym przykładem Threadbyłoby zainicjowanie klasy
Thread thread = new Thread(new ParameterizedThreadStart(Work));
Lub tylko
Thread thread = new Thread(Work);
Podpis odpowiedniej metody (wywołanej Workw 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 nulldane do metody, Start(...)może służyć do przekazywania wszystkiego do Workmetody wątku.
Jest jednak jeden duży problem z tym podejściem: wszystko przekazane do Workmetody jest rzutowane na obiekt. Oznacza to, że w ramach Workmetody 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 InvalidCastExceptionczymś, czego prawdopodobnie nie zauważysz, ponieważ po prostu kończy wątek.
Jako rozwiązanie można oczekiwać ogólnego ParameterizedThreadStartdelegata, na przykład, ParameterizedThreadStart<T>gdzie Tbyłby typ danych, które chcesz przekazać do Workmetody. 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 ;-)