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());

C# - 不可变的方法参数

使用克隆方法怎么样。这将在新内存中创建重新创建对象。因此,调用方法实例不会影响 HandleMessage 方法中的实例

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

TCPClient 是引用类型。因此,无论您是否将其作为 ref 传递,存储对象的内存都将被共享。当您将对象作为 ref 传递时,堆栈和内存将在方法之间共享。在没有 ref 参数的方法之间传递对象时,不会为对象分配新内存,而是创建一个指向相同内存位置的新堆栈条目。在这种情况下,您需要将数据复制到新的内存位置,以便克隆将完全做到这一点。

字符串是不可变的,因此当您通过线程传递 DoStuff 方法中的值并更改调用方法中的值时,它不会影响 DoStuff 方法。每次初始化''重新分配字符串时,都会分配一个新的内存。我认为您为字符串示例陈述的行为是不可能的。除非如@Dotnet所指出的,否则线程可能尚未启动,而您已将值重新分配给再见...这称为闭包,解决它的方法是创建该字符串变量的副本并在方法中传递该副本

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