Как передать параметры 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);
}