Как передать параметры методу ThreadStart в Thread? - PullRequest
271 голосов
/ 29 июля 2010

Как передать параметры в метод Thread.ThreadStart() в C #?

Предположим, у меня есть метод 'download'

public void download(string filename)
{
    // download code
}

Теперь я создал одну нить в основном методе:

Thread thread = new Thread(new ThreadStart(download(filename));

Ожидается тип метода ошибки.

Как передать параметры в ThreadStart с помощью метода target с параметрами?

Ответы [ 9 ]

659 голосов
/ 29 июля 2010

Самое простое это просто

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

Преимущество (я) этого (более ParameterizedThreadStart) в том, что вы можете передавать несколько параметров, и вы получаете проверку во время компиляции без необходимости постоянно приводить из object.

34 голосов
/ 29 июля 2010

Посмотрите на этот пример:

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);

Но ваш метод загрузки все равно должен принимать объект , а не string в качестве параметра. Вы можете привести его к строке в теле вашего метода.

23 голосов
/ 29 июля 2010

Вы хотите использовать делегат ParameterizedThreadStart для потоковых методов, которые принимают параметры.(Или вообще ничего, и пусть конструктор Thread выводит.)

Пример использования:

var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent

thread.Start(filename)
4 голосов
/ 09 октября 2014

Вы могли бы также delegate, как так ...

ThreadStart ts = delegate
{
      bool moreWork = DoWork("param1", "param2", "param3");
      if (moreWork) 
      {
          DoMoreWork("param1", "param2");
      }
};
new Thread(ts).Start();
2 голосов
/ 29 сентября 2017

В дополнительном

    Thread thread = new Thread(delegate() { download(i); });
    thread.Start();
2 голосов
/ 22 июля 2016

Вы можете инкапсулировать функцию потока (загрузка) и необходимые параметры (и) (имя файла) в классе и использовать делегат 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);
0 голосов
/ 08 декабря 2018

По вашему вопросу ...

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

Таким образом, вы просто избегаете обхода и имеете безопасный для передачи данных потоку; -)

0 голосов
/ 24 ноября 2016

вот идеальный способ ...

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);
}
0 голосов
/ 21 февраля 2015

Как насчет этого: (или это нормально использовать как это?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
    try
    {
        //Staff to do
        Console.WriteLine(test);
    }
    catch (Exception ex)
    {
        throw;
    }
})).Start();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...