C# - 不可变的方法参数
本文关键字:方法 参数 不可变 | 更新日期: 2023-09-27 18:36:30
有没有办法在 C# 方法中使用不可变参数?下面我有一些信使应用程序的代码,它给我带来了一些问题。这个想法是有一个服务器可以处理多个客户端。该代码的工作原理是创建一个监视传入连接的TcpListener
,获取基础TcpClient
的 IP 地址(通过NetworkStream
作为字符串发送),启动一个将处理来自该客户端的消息的新线程,然后侦听更多连接。主要问题是client
对象传入新Thread
后,主代码循环,在等待另一个连接的同时将client
的值设置为null
。
错误类型:System.InvalidOperationException
错误消息:The operation is not allowed on non-connected sockets.
这对我来说是,handleMessages
线程内的TcpClient
值受到.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)
如果有什么不清楚的地方,请告诉我!我可能和你一样困惑!
更新/解决方案:对于将来需要它的任何人,根据Viru的回答,这就是解决问题的方式:
Thread messageWatcher = new Thread(() => handleMessages(client.Clone());
使用克隆方法怎么样。这将在新内存中创建重新创建对象。因此,调用方法实例不会影响 HandleMessage 方法中的实例
Thread messageWatcher = new Thread(() => handleMessages(client.Clone()));
TCPClient 是引用类型。因此,无论您是否将其作为 ref 传递,存储对象的内存都将被共享。当您将对象作为 ref 传递时,堆栈和内存将在方法之间共享。在没有 ref 参数的方法之间传递对象时,不会为对象分配新内存,而是创建一个指向相同内存位置的新堆栈条目。在这种情况下,您需要将数据复制到新的内存位置,以便克隆将完全做到这一点。
字符串是不可变的,因此当您通过线程传递 DoStuff 方法中的值并更改调用方法中的值时,它不会影响 DoStuff 方法。每次初始化''重新分配字符串时,都会分配一个新的内存。我认为您为字符串示例陈述的行为是不可能的。除非如@Dotnet所指出的,否则线程可能尚未启动,而您已将值重新分配给再见...这称为闭包,解决它的方法是创建该字符串变量的副本并在方法中传递该副本
var copy = data;
Thread doStuff = new Thread(() => DoStuff(copy));