2016-02-28 127 views
2

有什麼辦法可以在C#方法中擁有不可變參數嗎?下面我給一些messenger應用程序提供了一些代碼,這些代碼給了我一些問題。這個想法是有一臺服務器可以處理多個客戶端。該代碼通過創建TcpListener來監視傳入連接,獲取底層TcpClient(通過NetworkStream作爲字符串發送)的IP地址,啓動一個處理來自該客戶端的消息的新線程,然後監聽更多連接。主要問題是client對象被傳遞到新的Thread後,主代碼將循環並在等待另一個連接時將值client設置爲nullC# - 不可變的方法參數

錯誤類型:System.InvalidOperationException 錯誤消息:The operation is not allowed on non-connected sockets.

這是什麼對我說的是,TcpClient的的handleMessages線程內在價值正受到該線程的.Start()方法啓動後會發生什麼client

這裏是我的代碼:

private void watchForConnections() 
{ 
    TcpListener listener = new TcpListener(IPAddress.Any, this.Port); //Listener that listens on the specified port for incoming clients 
    listener.Start(); 
    TcpClient client = new TcpClient(); 
    do 
    { 
     client = listener.AcceptTcpClient(); //Wait for connection request 
     StreamReader reader = new StreamReader(client.GetStream()); 
     string clientIP = reader.ReadLine(); //Use the StreamReader to read the IP address of the client 
     RelayMessage("SERVER_NEW_" + clientIP + "_" + DateTime.Now.ToString("HH:mm:ss")); //Tell all machines who just connected 
     Thread messageWatcher = new Thread(() => handleMessages(client)); 
     messageWatcher.Start(); //Start new thread to listen for messages from that specific client 
    } while (AllowingConnections == true); 
    listener.Stop(); 
} 

private void handleMessages(TcpClient _client) 
{ 
    using (StreamReader readMsg = new StreamReader(_client.GetStream())) //I get the error here 
    using (StreamWriter writeMsg = new StreamWriter(_client.GetStream())) //And here 
    { 
     //Handle messages from client here 
    } 
} 

我的問題:有什麼辦法可以在handleMessages參數將不被會發生什麼方法之外有什麼影響?迄今爲止,我的研究並沒有涉及到這個問題,或者任何類似的問題。我需要的是有點像ref參數的反面。也許我只是沒有在尋找正確的東西。我不知道我是否解釋正確。

用繩子又如:

string data = "hello"; 
Thread doStuff = new Thread(() => DoStuff(data)); //Value of data is equal to: "hello" 
doStuff.Start(); 
data = "goodbye"; //I want the value of the string in the doStuff thread to still be: "hello", not "goodbye" (Don't reflect changes made to string after thread is started/method is called) 

如果有什麼不清楚,請讓我知道!我可能和你一樣困惑!

UPDATE /解決方案: 的人誰需要它的未來,這是問題是如何解決的,按照維魯的回答是:

Thread messageWatcher = new Thread(() => handleMessages(client.Clone()); 
+0

你爲什麼不這樣稱呼它複製'DoStuff(string.Copy(數據))' ,從而創建一個新的'數據'的無關副本? – dotNET

+0

創建副本。 'var copy = data'? –

+0

這已經在這裏討論:http://stackoverflow.com/questions/2339074/can-parameters-be-constant –

回答

2

如何使用Clone方法。這將創建在新的內存中重新創建對象。因此,在方法的handleMessage您的調用方法實例不會影響實例

Thread messageWatcher = new Thread(() => handleMessages(client.Clone())); 

的TcpClient是引用類型。所以不管你把它作爲ref或沒有在對象存儲將是shared..When你的記憶傳遞一個對象作爲ref,然後堆棧以及方法之間共享內存。當您在不帶ref參數的方法之間傳遞對象時,不會爲對象分配新的內存,而是會創建一個指向相同內存位置的新堆棧條目。在這種情況下,您需要將數據複製到新的內存位置,以便克隆將完成該操作。

關於你的第二個例子。字符串是不可變的,因此當您通過線程在DoStuff方法中傳遞值並更改調用方法中的值時,它不會影響DoStuff方法。每次初始化\重新分配一個字符串都會分配一個新的內存。我不認爲你爲字符串例子指出的行爲是可能的。除非@Dotnet指出,線程可能還沒有開始,同時你已經重新分配了價值......這就是所謂的關閉和方法來解決它是創建一個字符串變量和通副本,在該方法

var copy = data; 
Thread doStuff = new Thread(() => DoStuff(copy)); 
+0

感謝您的快速響應;這正是我正在尋找的!你碰巧對這個問題的標題應該有什麼想法? –

+0

@MicahVertal標題對我來說很好看...... – Viru

+0

好的,我只是不確定標題是否與問題明顯相關。再次感謝! –