De acordo com sua pergunta ...
Como passar parâmetros para o método Thread.ThreadStart () em C #?
... e o erro encontrado, você precisaria corrigir seu código de
Thread thread = new Thread(new ThreadStart(download(filename));
para
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
No entanto, a questão é mais complexa, como parece à primeira vista.
A Thread
classe atualmente (4.7.2) fornece vários construtores e um Start
método com sobrecargas.
Esses construtores relevantes para esta pergunta são:
public Thread(ThreadStart start);
e
public Thread(ParameterizedThreadStart start);
que leva um ThreadStart
delegado ou um ParameterizedThreadStart
delegado.
Os delegados correspondentes ficam assim:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Portanto, como pode ser visto, o construtor correto a ser usado parece ser aquele que recebe um ParameterizedThreadStart
delegado, para que algum método em conformidade com a assinatura especificada do delegado possa ser iniciado pelo encadeamento.
Um exemplo simples para instanciar a Thread
classe seria
Thread thread = new Thread(new ParameterizedThreadStart(Work));
ou apenas
Thread thread = new Thread(Work);
A assinatura do método correspondente (chamada Work
neste exemplo) se parece com isso:
private void Work(object data)
{
...
}
O que resta é iniciar o thread. Isso é feito usando qualquer um
public void Start();
ou
public void Start(object parameter);
Enquanto Start()
iniciaria o encadeamento e passaria null
como dados para o método, Start(...)
pode ser usado para passar qualquer coisa para o Work
método do encadeamento.
No entanto, há um grande problema com essa abordagem: tudo o Work
que é passado no método é convertido em um objeto. Isso significa que, dentro do Work
método, ele deve ser convertido para o tipo original novamente, como no exemplo a seguir:
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}");
}
A transmissão é algo que você normalmente não deseja fazer.
E se alguém passa outra coisa que não é uma string? Como isso parece inicialmente impossível (porque é o meu método, eu sei o que faço ou O método é privado, como alguém deve ser capaz de transmitir alguma coisa a ele? ), Você pode acabar exatamente com esse caso por vários motivos . Como alguns casos podem não ser um problema, outros são. Nesses casos, você provavelmente terminará com um InvalidCastException
que provavelmente não notará porque simplesmente encerra o encadeamento.
Como solução, você esperaria obter um ParameterizedThreadStart
representante genérico como ParameterizedThreadStart<T>
onde T
seria o tipo de dados que você deseja passar para o Work
método. Infelizmente, algo assim não existe (ainda?).
Existe, no entanto, uma solução sugerida para esse problema. Envolve a criação de uma classe que contém os dados a serem passados para o encadeamento, bem como o método que representa o método worker como este:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Com essa abordagem, você iniciaria o thread assim:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Dessa forma, você simplesmente evita a transmissão e tem uma maneira tipicamente segura de fornecer dados para um thread ;-)