По твоему вопросу ...
Как передать параметры в метод Thread.ThreadStart () в C #?
... и ошибка, с которой вы столкнулись, вам придется исправить свой код с
Thread thread = new Thread(new ThreadStart(download(filename));
в
Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
Тем не менее, вопрос более сложен, как кажется на первый взгляд.
В Thread
настоящее время класс (4.7.2) предоставляет несколько конструкторов и Start
метод с перегрузками.
Эти соответствующие конструкторы для этого вопроса:
public Thread(ThreadStart start);
и
public Thread(ParameterizedThreadStart start);
которые либо принимают ThreadStart
делегата, либо ParameterizedThreadStart
делегата.
Соответствующие делегаты выглядят так:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Итак, как можно видеть, правильный конструктор, который нужно использовать, - это тот, который принимает ParameterizedThreadStart
делегат, так что поток, соответствующий некоторому методу, соответствующему указанной сигнатуре делегата, может быть запущен потоком.
Простой пример создания экземпляра Thread
класса:
Thread thread = new Thread(new ParameterizedThreadStart(Work));
или просто
Thread thread = new Thread(Work);
Сигнатура соответствующего метода (вызываемого Work
в этом примере) выглядит следующим образом:
private void Work(object data)
{
...
}
Осталось только начать тему. Это делается с помощью либо
public void Start();
или
public void Start(object parameter);
Хотя Start()
бы запустить поток и передать null
как данные в метод, Start(...)
может использоваться для передачи чего-либо в Work
метод потока.
Однако у этого подхода есть одна большая проблема: все, что передается в Work
метод, преобразуется в объект. Это означает, что в Work
методе он должен быть снова приведен к исходному типу, как в следующем примере:
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}");
}
Кастинг - это то, что вы обычно не хотите делать.
Что если кто-то пропустит что-то еще, не являющееся строкой? Поскольку вначале это кажется невозможным (поскольку это мой метод, я знаю, что я делаю, или метод частный, как кто-то может быть в состоянии что-либо передать ему? ), Вы можете в конечном итоге получить именно этот случай по разным причинам. , Поскольку некоторые случаи могут не быть проблемой, другие - нет. В таких случаях вы, вероятно, в конечном итоге InvalidCastException
получите, который вы, вероятно, не заметите, потому что он просто завершает поток.
В качестве решения вы ожидаете получить общий ParameterizedThreadStart
делегат, например, ParameterizedThreadStart<T>
где T
будет тип данных, которые вы хотите передать в Work
метод. К сожалению что-то подобное не существует (пока?).
Однако есть предложенное решение этой проблемы. Он включает в себя создание класса, который содержит как данные, которые будут переданы потоку, так и метод, который представляет рабочий метод следующим образом:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
При таком подходе вы начинаете поток так:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Таким образом, вы просто избегаете перебора и имеете безопасный способ предоставления данных потоку ;-)