如何在线程中传递参数到ThreadStart方法?

如何在c#中传递参数给Thread.ThreadStart()方法?

假设我有一个叫做download的方法

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

现在我已经在main方法中创建了一个线程:

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

预期的方法类型错误。

我如何通过参数的目标方法ThreadStart参数?

410156 次浏览

最简单的就是

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

这(相对于ParameterizedThreadStart)的优点是你可以传递多个参数,并且你得到编译时检查,而不需要一直从object强制转换。

你想要为接受参数的线程方法使用ParameterizedThreadStart委托。(或者实际上没有,让Thread构造函数来推断。)

使用示例:

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


thread.Start(filename)

看看这个例子:

public void RunWorker()
{
Thread newThread = new Thread(WorkerMethod);
newThread.Start(new Parameter());
}


public void WorkerMethod(object parameterObj)
{
var parameter = (Parameter)parameterObj;
// do your job!
}

你首先通过将delegate传递给worker方法来创建一个线程,然后用thread启动它。Start方法,该方法将对象作为参数。

所以在你的例子中,你应该这样使用它:

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

但是你的“download”方法仍然需要将对象作为参数,而不是字符串。你可以在方法体中将其转换为字符串。

你也可以像这样delegate

ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param1", "param2");
}
};
new Thread(ts).Start();

这样怎么样:(或者可以这样用吗?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
try
{
//Staff to do
Console.WriteLine(test);
}
catch (Exception ex)
{
throw;
}
})).Start();

您可以将线程函数(下载)和所需的参数(文件名)封装在一个类中,并使用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);

这里有一个完美的方法……

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

在额外的

    Thread thread = new Thread(delegate() { download(i); });
thread.Start();

根据你的问题…

如何在c#中传递参数给Thread.ThreadStart()方法?

...对于你遇到的错误,你必须纠正你的代码

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

Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);
< p > < br > < br > 然而,这个问题比最初看起来的要复杂得多

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}");
}
< p > < br > < br > 强制转换通常是您不想做的事情。 < br > < br > 如果有人传递其他不是字符串的东西怎么办?因为一开始这似乎是不可能的(因为这是我的方法,我知道我在做什么方法是私有的,怎么能有人把东西传递给它呢?),你可能会因为各种原因而最终出现这种情况。有些情况下可能不是问题,其他情况则是。在这种情况下,你可能会得到InvalidCastException,你可能不会注意到,因为它只是结束了线程

作为一种解决方案,你会期望获得一个通用的ParameterizedThreadStart委托,如ParameterizedThreadStart<T>,其中T将是你想传递给Work方法的数据类型。不幸的是,这样的东西还不存在(目前?)

然而,这个问题有一个建议的解决方案。它涉及到创建一个类,其中包含传递给线程的数据以及表示worker方法的方法,如下所示:

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

因此,通过这种方式,您可以简单地避免强制转换,并以类型安全的方式向线程提供数据;-)

我建议你学习另一门叫做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);