2010-02-11 32 views
0

我已經創建了一個實現運行在一個單獨的線程另一種抽象方法,這樣的方法的抽象類:如何在原始線程上更改傳遞給在單獨線程上運行的函數的值?

public abstract class ATest 
    { 
     Thread t; 
     protected String status; 
     public void Start() 
     { 
      ThreadStart ts = new ThreadStart(PerformTest); 
      t = new Thread(ts); 
      t.Start(); 

     } 

     public ATest(String status) 
     { 
      this.status=status; 
     } 
     public abstract void PerformTest(); 
    } 

的想法是,從ATEST派生類僅實現PerformTest方法。因此,任何客戶端都可以調用Start()方法在其自己的線程上啓動PerformTest()內的操作。從ATEST的類派生可能看起來像:

class ConcreteTest:ATest 
    { 
     public ConcreteTest(String status):base(status) 
     { 

     } 

     public override void PerformTest() 
     { 
      // Do some things... 
      // And some more... 
      status = "changed"; 
     } 

    } 

在創建ConcreteTest對象我想在某些對象來傳遞(在本例中的String)。當PerformTest()在其獨立線程上運行時,此對象的狀態將根據PerformTest()中的操作結果進行更改。使用上述類的例子:

class Program 
{ 
    static void Main(string[] args) 
    { 
     String isPassed = "original"; 
     ATest test = new ConcreteTest(isPassed); 
     test.Start(); 
     Console.WriteLine(isPassed); // Prints out "original" 
    } 
} 

所以我設置isPassed爲「originial」並將其傳遞給ConcreteTest,其在一個單獨的線程變爲值設置爲「改變」。所以,當我打印出isPassed我希望的價值被設置爲「改變」,但事實證明它不是。我想這與另一個線程上最初創建的線程上的值發生了變化。任何人都可以向我解釋爲什麼我會得到這種行爲,也許我可以做些什麼來實現我正在尋找的功能(即在單獨的線程上更改isPassed,以便線程完成後控制檯將打印出來「改變」?

+0

您是否將一份副本傳遞給抽象類? 爲什麼你期望它改變? – gbianchi

回答

1

字符串是不可改變的。

當你寫status = "changed",你不改變任何現有的字符串對象。
相反,你正在改變status場是指一個完全不同的 String實例。

status fie ld與Main方法中的isPassed變量無關。當您編寫new ConcreteTest(isPassed)時,您將isPassed變量的傳遞給構造函數。
該參數與您傳遞給它的變量無關,除了現在它們碰巧指向同一個對象。您的status字段也是如此。

要做到這一點,最簡單的方法是定義一個支架類型,像這樣:

class Holder<T> { public T Value { get; set; } } 

如果你願意,你可以添加隱式轉換和構造函數。

您也可以通過在您的基類中公開Status屬性並在Main中寫入test.Status來做到這一點。


你也有一個不太明顯的問題。
代碼中沒有任何東西強制它等待另一個線程完成,因此您的Console.WriteLine可能在該字段由另一個線程分配之前運行。

+1

「唯一的辦法」?編程中總是有很多方法可以做任何事情。 :-) –

+0

我認爲這個字符串是作爲一個對象進行處理的,因此通過引用而不是按照值傳遞。顯然,我錯了。你的解決方案解決了我的問題謝謝! –

+0

有一件事發生在我身上。當Holder是通用的時候,這是有效的,但是如果不把它定義爲通用的,它就不起作用。這是爲什麼? –

0

通常情況下,您需要將結果存儲在ConcreteTest中,並且任務完成後,請從ConcreteTest中讀取值,不要嘗試將其推回原始位置。如果你真的想把它推回去,你可以用這樣的回調和lambda來實現。

class ConcreteTest:ATest 
{ 
    public ConcreteTest(Action<string> statusResponder):base(statusResponder) 
    { 

    } 

    public override void PerformTest() 
    { 
     // Do some things... 
     // And some more... 
     statusResponder("changed"); 
    } 

} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     String isPassed = "original"; 
     ATest test = new ConcreteTest(status => isPassed = status); 
     test.Start(); 
     // Need to add a way to wait for task to be done here 
     Console.WriteLine(isPassed); // Prints out "original" 
    } 
} 
+0

重申您對我現在刪除的答案的評論:謝謝,我錯過了這個問題的方面。 –

+0

@ T.J。 Crowder,np,是一個很好的答案,僅僅是一個不同的問題。 :-) –

+0

我試過這個解決方案,但是我得到了完全相同的結果。 :( –

相關問題