需要在使用 TcpClient 的类上实现终结器吗?

发布于 2024-07-13 17:47:35 字数 368 浏览 14 评论 0原文

我有一个类(例如 MyClass),它使用(作为私有字段)一个 TcpClient 对象。 MyClass 实现了 IDisposable,在 Dispose 方法中调用 TcpClient.Close

我的问题是 MyClass 是否还应该实现一个终结器来调用 Dispose(bool Dispose) 来释放 TcpClient 非托管资源,以防 MyClass. Dispose 没有被调用代码调用?

谢谢

I have a class (say MyClass) that uses (has as a private field) a TcpClient object. MyClass implements IDisposable calling TcpClient.Close in the Dispose method.

My question is should MyClass also implement a finalizer to call Dispose(bool Disposing) to free the TcpClient’s unmanaged resources in case MyClass.Dispose is not called by the calling code?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心病无药医 2024-07-20 17:47:35

不,你不应该。

因为你不应该在终结器中调用其他对象的方法,它可能在你的对象之前被终结。

TcpClient 的终结器将由垃圾收集器调用,所以让他来做吧。

Dispose 中的模式是:

protected virtual void Dispose(bool disposing)
{
   if (disposing)
   { 
      // dispose managed resources (here your TcpClient)
   }

   // dispose your unmanaged resources 
   // handles etc using static interop methods.
}

No you shouldn't.

Because you should never call a method on an other object in a finalizer, it could have been finalized before your object.

The finalizer of your TcpClient will be called by the garbage collector, so let him do.

The pattern in Dispose is :

protected virtual void Dispose(bool disposing)
{
   if (disposing)
   { 
      // dispose managed resources (here your TcpClient)
   }

   // dispose your unmanaged resources 
   // handles etc using static interop methods.
}
情痴 2024-07-20 17:47:35

不,你不应该。

来自 此优秀的帖子:

最终确定是根本
与结束对象不同
寿命。 从正确性的角度来看
视图之间没有顺序
终结器(特殊情况除外)
对于关键终结器),所以如果你
有两个 GC 认为的对象
同时死了,你不能
预测哪个终结器将完成
第一的。 这意味着您不能拥有
与任何交互的终结器
存储在实例中的可终结对象
变量。

这是我的一次性/最终化模式的参考实现,其中包含解释何时使用的注释:

/// <summary>
    /// Example of how to implement the dispose pattern.
    /// </summary>
    public class PerfectDisposableClass : IDisposable
    {
        /// <summary>
        /// Type constructor.
        /// </summary>
        public PerfectDisposableClass()
        {
            Console.WriteLine( "Constructing" );    
        }

        /// <summary>
        /// Dispose method, disposes resources and suppresses finalization.
        /// </summary>
        public void Dispose()
        {
            Dispose( true );
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Disposes resources used by class.
        /// </summary>
        /// <param name="disposing">
        /// True if called from user code, false if called from finalizer.
        /// When true will also call dispose for any managed objects.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            Console.WriteLine( "Dispose(bool disposing) called, disposing = {0}", disposing );

            if (disposing)
            {
                // Call dispose here for any managed objects (use lock if thread safety required), e.g.
                // 
                // if( myManagedObject != null )
                // {
                //     myManagedObject.Dispose();
                //     myManagedObject = null;
                //  }
            }
        }

        /// <summary>
        /// Called by the finalizer.  Note that if <see cref="Dispose()"/> has been called then finalization will 
        /// have been suspended and therefore never called.
        /// </summary>
        /// <remarks>
        /// This is a safety net to ensure that our resources (managed and unmanaged) are cleaned up after usage as
        /// we can guarantee that the finalizer will be called at some point providing <see cref="Dispose()"/> is
        /// not called.
        /// Adding a finalizer, however, IS EXPENSIVE.  So only add if using unmanaged resources (and even then try
        /// and avoid a finalizer by using <see cref="SafeHandle"/>).
        /// </remarks>
        ~PerfectDisposableClass()
        {
            Dispose(false);
        }
    }

No you shouldn't.

From this excellent post:

Finalization is fundamentally
different from ending an object’s
lifetime. From a correctness point of
view, there is no ordering between
finalizers (outside of a special case
for critical finalizers), so if you
have two objects that the GC thinks
are dead at the same time, you cannot
predict which finalizer will complete
first. This means you can’t have a
finalizer that interacts with any
finalizable objects stored in instance
variables.

This is my reference implementation of the disposable/finalize pattern with comments explaining when to use what:

/// <summary>
    /// Example of how to implement the dispose pattern.
    /// </summary>
    public class PerfectDisposableClass : IDisposable
    {
        /// <summary>
        /// Type constructor.
        /// </summary>
        public PerfectDisposableClass()
        {
            Console.WriteLine( "Constructing" );    
        }

        /// <summary>
        /// Dispose method, disposes resources and suppresses finalization.
        /// </summary>
        public void Dispose()
        {
            Dispose( true );
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Disposes resources used by class.
        /// </summary>
        /// <param name="disposing">
        /// True if called from user code, false if called from finalizer.
        /// When true will also call dispose for any managed objects.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            Console.WriteLine( "Dispose(bool disposing) called, disposing = {0}", disposing );

            if (disposing)
            {
                // Call dispose here for any managed objects (use lock if thread safety required), e.g.
                // 
                // if( myManagedObject != null )
                // {
                //     myManagedObject.Dispose();
                //     myManagedObject = null;
                //  }
            }
        }

        /// <summary>
        /// Called by the finalizer.  Note that if <see cref="Dispose()"/> has been called then finalization will 
        /// have been suspended and therefore never called.
        /// </summary>
        /// <remarks>
        /// This is a safety net to ensure that our resources (managed and unmanaged) are cleaned up after usage as
        /// we can guarantee that the finalizer will be called at some point providing <see cref="Dispose()"/> is
        /// not called.
        /// Adding a finalizer, however, IS EXPENSIVE.  So only add if using unmanaged resources (and even then try
        /// and avoid a finalizer by using <see cref="SafeHandle"/>).
        /// </remarks>
        ~PerfectDisposableClass()
        {
            Dispose(false);
        }
    }
落日海湾 2024-07-20 17:47:35

不,你不必这样做。 TcpClient 是非托管套接字的包装类,并且以应有的方式对其进行管理。 你所做的就足够了。

No you don't have to. TcpClient is a wrapper class around the unmanaged socket and there for it is managed the way it should be disposed. What you have done is enough.

深白境迁sunset 2024-07-20 17:47:35

是的,您应该 - Microsoft 甚至推荐它

请记住,腰带和吊带代码永远不会让您在凌晨 2:00 被叫到办公室:)

Yes you should - Microsoft even recommends it.

Just remember that belt-and-suspenders code never gets you called into the office at 2:00AM :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文