【问题标题】:How can I use "using" in C# without getting "InvalidOperationException"?如何在 C# 中使用“使用”而不出现“InvalidOperationException”?
【发布时间】:2014-08-14 01:14:04
【问题描述】:

我正在尝试替换以下可以正常工作的代码

TcpClient oC = new TcpClient(ip, port);
oC = new TcpClient(ip, port);
StreamReader messageReader;

try {
   messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII);
   reply = messageReader.ReadLine();
}

try {
   using (messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
   {
       reply = messageReader.ReadLine();
   }
}

但我得到一个InvalidOperationException

该操作不允许 未连接的套接字。

问题是什么,我该如何解决?

更多:我在这段代码之前有 oc.Connect,所以我已连接,当它想第一次使用时工作正常,只有在那之后我才得到那个异常,我玩了一下,现在我得到了:

无法访问已处置的 对象。\r\n对象名称: 'System.Net.Sockets.Socket'。

【问题讨论】:

    标签: c# .net debugging tcpclient


    【解决方案1】:

    在创建 StreamReader 之前尝试调用 oc.Connect。在连接套接字之前,没有任何内容可以实际读取,因此会出现异常。

    【讨论】:

    • 我在此之前有 oc.Connect,它第一次工作正常,但第二次发生,我也得到“无法访问已处置的对象。\r\n对象名称:'System. Net.Sockets.Socket'。”
    • 那是因为 StreamReader 获得了流的所有权,并关闭并处置了您启动它的 Stream。在这种情况下,TcpClient 的 NetworkStream。无需在此处处理 StreamReader。
    【解决方案2】:

    只是重申我对 Jareds 答案的评论。

    阿里评论:

    在此之前我有 oc.Connect 和它 第一次工作正常,但是 第二次发生,我也得到 “无法访问已处置的 对象。\r\n对象名称: 'System.Net.Sockets.Socket'。”——阿里 (13 分钟前)

    我评论了:

    "那是因为 StreamReader 需要 流的所有权,并关闭 并处理您启动的 Stream 它与。在这种情况下, TcpClient 的 NetworkStream。有 无需处理 StreamReader 这里”

    【讨论】:

    • 那么,你是说我不能使用“使用”,我只需要保持原样?
    • @Ali,没有。您可以使用正确的构造函数来阻止 StreamReader 获取所有权并处理 Stream。看我的回答。
    • 现在确实发生了变化,谢天谢地,他们在构造函数中添加了 leaveOpen 布尔值。不过,早在 .NET 2.0 时代,它就不存在了。
    【解决方案3】:

    所以使用the right constructor

    using (messageReader = 
            new StreamReader(oC.GetStream(), Encoding.ASCII, false, 4096, true))
    {
       reply = messageReader.ReadLine();
    }
    

    注意最后一个参数leaveOpen: 并了解它在the docs 中的含义。

    但是,IIRC,StreamReader 缓冲流中的内容(默认情况下,读取 4096 字节),因此当您处理 StreamReader 时,您可能会惊讶地发现流的位置已经超出了您使用 StreamReader 读取的数据。允许 StreamReader 取得所有权通常总是一个好主意。在读取所有数据之前,您不能让它保持打开状态吗?

    【讨论】:

      【解决方案4】:

      另外,您将 messageReader 声明为 StreamWriter。不应该是 StreamReader 吗?

      StreamWriter messageReader;
      

      [由 OP 修复]

      另一个提示,最好在 using 语句中实例化一个对象,而不是将其传入。这可能不是您的异常的实际原因,而是from MSDN

      您可以实例化资源 对象,然后将变量传递给 using 语句,但这不是 最佳实践。在这种情况下, 控制后对象仍在范围内 离开 using 块,即使它 可能无法再访问 它的非托管资源。其他 话,它将不再是完全 初始化。如果您尝试使用 使用块之外的对象,你 导致异常的风险 抛出。为此,它是 通常更好地实例化 using 语句中的对象和 将其范围限制为 using 块。

      【讨论】:

      • 那是我的错误,我改正了。
      • 没问题,我已经在我的答案中添加了额外内容,可能会有所帮助。
      【解决方案5】:

      听听Jared,你的实际异常,使用与它无关,你的尝试可以掩盖错误并隐藏真正的问题。真正的错误是您在尝试读取之前从未真正连接过您的套接字。

      编辑:

      听起来正在发生的是,您连接一次,然后连接被切断或对象失去作用域。在这种情况下,您需要做的可能是捕获断开连接并重新创建最初用于连接到服务器的套接字。一旦处理了该套接字,您就不能再次使用相同的引用,您必须实例化一个新的引用并使用它。

      您是否有一个更完整的示例可以发布来显示您的连接范围与使用情况,以便我们可以准确了解 GC 拾取底层套接字的位置?

      【讨论】:

        【解决方案6】:

        我认为您不能先定义 StreamWriter,然后将其与 'using' 一起使用。

        试试这个:

        TcpClient oC = new TcpClient(ip, port);
        oC = new TcpClient(ip, port);
        
        try {
           using (StreamWriter messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
           {
               reply = messageReader.ReadLine();
           }
        }
        

        【讨论】:

        • 按照他的方式初始化流阅读器是完全合法的。
        • 这是合法的,但微软不推荐,请参阅 MSDN 或我的回答。
        猜你喜欢
        • 2015-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-12
        • 1970-01-01
        • 2021-12-04
        相关资源
        最近更新 更多