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