2016-02-28 128 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

好的,我只是不确定标题是否与问题明显相关。再次感谢! –