【问题标题】:Where to close a TcpClient member在哪里关闭 TcpClient 成员
【发布时间】:2012-04-11 18:03:58
【问题描述】:

上下文:我有一个实现“会话”的类,在其生命周期内维护与服务器的 TCP 连接。在构造函数中,我使用给定的 IP 地址和要连接的服务器端口创建一个 TcpClient 实例。

   public Session(IPAddress ipAddress)
   {
       Client = new TcpClient(ipAddress.ToString(), 1234); //create a client to a server which we will later use to work with
       DataStream = Client.GetStream(); //get the stream for later usage
   }

此会话的对象偶尔会向其关联的服务器发送和接收数据。

我现在的问题是:我应该在哪里关闭 TcpClient 及其底层 NetworkStream?

我应该实现 IDisposable 吗?但是如果我的班级的用户忘记调用 Dispose 会发生什么?

我应该实现析构函数(又名终结器)吗?但是我不应该从那里访问托管资源?

感谢您帮助我!

【问题讨论】:

  • @abatishchev:虽然我喜欢听取建议,但我无法遵循您编辑的意图。我发现,代码格式和对问题重要部分的强调很有帮助。此外,提到 TcpClient 的“会员”质量的标题也意味着将问题与其他问题区分开来,尤其是避免建议使用“使用”。请向我解释您编辑的意图。

标签: c# tcp destructor idisposable


【解决方案1】:

我应该实现 IDisposable 吗?

是的

但是如果我班级的用户忘记调用 Dispose 会发生什么?

您应该遵循此处定义的一次性模式:http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

【讨论】:

  • 感谢您的提示。令我不安的是,总是存在“非托管”资源的概念。我应该如何处理我的 TcpClient。对我来说,这是一个托管资源。在 Dispose 方法中处理和调用 close 时,我可以将其视为“非托管”吗?
  • .NET 中实现IDisposable 的所有东西(嗯,几乎所有东西)都有非托管资源。因此需要处理实现IDisposable 的.NET 类。您当然可以让 GC 处理 TcpClient(当它感觉如此时),但我更喜欢在完成资源后立即释放它们。
  • 因此在包装 .NET 类时不需要终结器,但使用 Disposable 模式(但没有终结器)允许您的用户直接释放资源。
【解决方案2】:

查看“When should I Implment IDisposable?”上的无数主题

您的触发器,因为您有一个实现 IDisposable 的字段 (Client)。因此,您的课程应该是一次性的。

【讨论】:

    【解决方案3】:

    很少有类应该有清理终结器。如果负责管理IDisposable 实例的代码在放弃之前忽略了调用IDisposable.Dispose,则应修复该代码。添加终结器可能会掩盖问题,但不会解决问题,并且很可能会引入 Heisenbugs™。此外,如果一个类负责实现 IDisposable 并具有终结器的事物,则该类将需要确保调用这些事物的 Dispose 方法(可能来自其自己的 Dispose 方法),但不负责从它自己调用这些东西的终结器。事实上,当一个类的终结器正在运行时,对于它持有引用的任何可终结对象,以下三件事中的一件通常是正确的:

    1. 它已经完成了。
    2. 在当前终结器完成后,它已经在队列中等待最终确定。
    3. 对它的实时引用将存在于其他地方,并且不应该被清理。

    在任何这些情况下,终结器对对象的正确处理是“无”。

    【讨论】:

    • 我同意,“应该修复”。但是我正在开发一个供其他人使用的库,并且我想确保我的库不会引入资源泄漏,即使我的代码的其他用户是一个草率的程序员。
    • @Marcel:终结者引入了很多很难解决的棘手问题。此外,即使编写得非常完美,他们也会经常将那些会以清晰明了的方式失败的代码变成可以在 99% 的时间内工作但可能会以奇怪和晦涩的方式失败的代码。例如,如果一个对象在字段r 中拥有一个资源,则该对象的方法做的最后一件事就是使用该资源,并且在调用该方法后立即放弃对该对象的最后一个幸存引用,可能会触发终结器当该资源仍在使用中时
    • @Marcel:如果您的客户正确使用Dispose,则不会发生上述问题,因为在调用Dispose以外的其他方法时放弃最后一个幸存的引用将暗示客户不是'不会打电话给Dispose。另一方面,如果客户端正确使用Dispose,终结器将无关紧要。虽然在某些情况下我们不能合理地期望客户端使用Dispose 无用的对象,但在大多数情况下,如果Disposed 对象被挂起,而不是终结器尝试修复它们,调试客户端代码会更容易。
    猜你喜欢
    • 2018-04-25
    • 2011-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多