Как передать параметры методу ThreadStart в Thread?
Как передать параметры в Thread.ThreadStart()
метод в C#?
Предположим, у меня есть метод под названием "скачать"
public void download(string filename)
{
// download code
}
Теперь я создал один поток в основном методе:
Thread thread = new Thread(new ThreadStart(download(filename));
ожидаемый тип ошибки
Как я могу передать параметры ThreadStart
с целевым методом с параметрами?
9 ответов
Самое простое просто
string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();
Преимущество (с) этого (над ParameterizedThreadStart
является то, что вы можете передать несколько параметров, и вы получите проверку во время компиляции без необходимости приведения из object
все время.
Посмотрите на этот пример:
public void RunWorker()
{
Thread newThread = new Thread(WorkerMethod);
newThread.Start(ParameterObject);
}
public void WorkerMethod(object parameterObject)
{
// do your job!
}
Сначала вы создаете поток, передавая делегат в рабочий метод, а затем запускаете его с помощью метода Thread.Start, который принимает ваш объект в качестве параметра.
Так что в вашем случае вы должны использовать это так:
Thread thread = new Thread(download);
thread .Start(filename);
Но ваш метод загрузки все равно должен принимать объект, а не строку в качестве параметра. Вы можете привести его к строке в теле вашего метода.
Вы хотите использовать ParameterizedThreadStart
делегат для потоковых методов, которые принимают параметры. (Или вообще ничего, и пусть Thread
конструктор выведет.)
Пример использования:
var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent
thread.Start(filename)
Вы могли бы также delegate
вот так...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param1", "param2");
}
};
new Thread(ts).Start();
В дополнение
Thread thread = new Thread(delegate() { download(i); });
thread.Start();
Я бы порекомендовал вам иметь другой класс под названием 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);
Вы можете инкапсулировать функцию потока (загрузить) и необходимый параметр (ы)(имя файла) в классе и использовать делегат 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);
Как насчет этого: (или это нормально использовать как это?)
var test = "Hello";
new Thread(new ThreadStart(() =>
{
try
{
//Staff to do
Console.WriteLine(test);
}
catch (Exception ex)
{
throw;
}
})).Start();
По твоему вопросу...
Как передать параметры в метод 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();
Таким образом, вы просто избегаете перебора и имеете безопасный способ передачи данных в поток;-)
Вот идеальный способ...
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);
}