c#用匿名方法传递参数给线程(可不用拆箱和装箱,传任意个参数)
c#用匿名方法传递参数给线程(可不用拆箱和装箱,传任意个参数)
将数据传入ThreadStart中
话又说回来,在上面的例子里,我们想更好地区分开每个线程的输出结果,让其中一个线程输出大写字母。我们传入一个状态字到Go中来完成整个任务,但我们不能使用ThreadStart委托,因为它不接受参数,所幸的是,.NET framework定义了另一个版本的委托叫做ParameterizedThreadStart, 它可以接收一个单独的object类型参数:
public delegate void ParameterizedThreadStart (object obj);
之前的例子看起来是这样的:
class ThreadTest {
static void Main() {
Thread t = new Thread (Go);
t.Start (true); // == Go (true)
Go (false);
}
static void Go (object upperCase) {
bool upper = (bool) upperCase;
Console.WriteLine (upper ? "HELLO!" : "hello!");
}
hello!
HELLO!
在整个例子中,编译器自动推断出ParameterizedThreadStart委托,因为Go方法接收一个单独的object参数,就像这样写:
Thread t = new Thread (new ParameterizedThreadStart (Go));
t.Start (true);
ParameterizedThreadStart的特性是在使用之前我们必需对我们想要的类型(这里是bool)进行装箱操作,并且它只能接收一个参数。
一个替代方案是使用一个匿名方法调用一个普通的方法如下:
static void Main() {
Thread t = new Thread (delegate() { WriteText ("Hello"); });
t.Start();
}
static void WriteText (string text) { Console.WriteLine (text); }
优点是目标方法(这里是WriteText),可以接收任意数量的参数,并且没有装箱操作。不过这需要将一个外部变量放入到匿名方法中,向下面的一样:
static void Main() {
string text = "Before";
Thread t = new Thread (delegate() { WriteText (text); });
text = "After";
t.Start();
}
static void WriteText (string text) { Console.WriteLine (text); }
After
匿名方法打开了一种怪异的现象,当外部变量被后来的部分修改了值的时候,可能会透过外部变量进行无意的互动。有意的互动(通常通过字段)被认为是足够了!一旦线程开始运行了,外部变量最好被处理成只读的——除非有人愿意使用适当的锁。
另一种较常见的方式是将对象实例的方法而不是静态方法传入到线程中,对象实例的属性可以告诉线程要做什么,如下列重写了原来的例子:
class ThreadTest {
bool upper;
static void Main() {
ThreadTest instance1 = new ThreadTest();
instance1.upper = true;
Thread t = new Thread (instance1.Go);
t.Start();
ThreadTest instance2 = new ThreadTest();
instance2.Go(); // 主线程——运行 upper=false
}
void Go() { Console.WriteLine (upper ? "HELLO!" : "hello!"); }