Как передать параметры ThreadStart в Thread?
Как передать параметры методу Thread.ThreadStart()
в С#?
Предположим, что у меня есть метод под названием 'download'
public void download(string filename)
{
// download code
}
Теперь я создал один поток в основном методе:
Thread thread = new Thread(new ThreadStart(download(filename));
тип метода ошибки ожидается.
Как передать параметры ThreadStart
с помощью целевого метода с параметрами?
Ответы
Ответ 1
Самый простой - это просто
string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();
Преимущество этого (более ParameterizedThreadStart
) заключается в том, что вы можете передавать несколько параметров, и вы получаете проверку времени компиляции без необходимости делать из object
все время.
Ответ 2
Посмотрите на этот пример:
public void RunWorker()
{
Thread newThread = new Thread(WorkerMethod);
newThread.Start(new Parameter());
}
public void WorkerMethod(object parameterObj)
{
var parameter = (Parameter)parameterObj;
// do your job!
}
Сначала вы создаете поток, передавая делегат в рабочий метод, а затем запускаете его с помощью метода Thread.Start, который принимает ваш объект в качестве параметра.
Так что в вашем случае вы должны использовать это так:
Thread thread = new Thread(download);
thread.Start(filename);
Но ваш метод загрузки все равно должен принимать объект, а не строку в качестве параметра. Вы можете привести его к строке в теле вашего метода.
Ответ 3
Вы хотите использовать делегат ParameterizedThreadStart
для потоков, которые принимают параметры. (Или вообще нет, и пусть конструктор Thread
делает вывод.)
Пример использования:
var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent
thread.Start(filename)
Ответ 4
Вы также можете delegate
так...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param1", "param2");
}
};
new Thread(ts).Start();
Ответ 5
Я бы порекомендовал вам другой класс с именем File.
public class File
{
private string filename;
public File(string filename)
{
this.filename= filename;
}
public void download()
{
// download code using filename
}
}
И в своем коде создания потока вы создаете новый файл:
string filename = "my_file_name";
myFile = new File(filename);
ThreadStart threadDelegate = new ThreadStart(myFile.download);
Thread newThread = new Thread(threadDelegate);
Ответ 6
Вы можете инкапсулировать функцию потока (загрузить) и необходимые параметры (имя файла) в классе и использовать делегат ThreadStart для выполнения функции потока.
public class Download
{
string _filename;
Download(string filename)
{
_filename = filename;
}
public void download(string filename)
{
//download code
}
}
Download = new Download(filename);
Thread thread = new Thread(new ThreadStart(Download.download);
Ответ 7
В дополнительном
Thread thread = new Thread(delegate() { download(i); });
thread.Start();
Ответ 8
Как насчет этого: (или это нормально использовать как это?)
var test = "Hello";
new Thread(new ThreadStart(() =>
{
try
{
//Staff to do
Console.WriteLine(test);
}
catch (Exception ex)
{
throw;
}
})).Start();
Ответ 9
По твоему вопросу...
Как передать параметры в метод Thread.ThreadStart() в С#?
... и ошибка, с которой вы столкнулись, вам придется исправить свой код с
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 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();
Таким образом, вы просто избегаете перебора и имеете безопасный способ предоставления данных потоку ;-)
Ответ 10
вот идеальный способ...
private void func_trd(String sender)
{
try
{
imgh.LoadImages_R_Randomiz(this, "01", groupBox, randomizerB.Value); // normal code
ThreadStart ts = delegate
{
ExecuteInForeground(sender);
};
Thread nt = new Thread(ts);
nt.IsBackground = true;
nt.Start();
}
catch (Exception)
{
}
}
private void ExecuteInForeground(string name)
{
//whatever ur function
MessageBox.Show(name);
}