Как передать параметры методу 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);
}
Другие вопросы по тегам