自定义初始化函数与IDisposable

本文关键字:IDisposable 函数 初始化 自定义 | 更新日期: 2023-09-27 18:08:18

在。net (c#)中,我遵循一些需要构造函数、初始化函数和IDisposable实现的自定义约定和模式。一个典型的类如下所示。没有在构造函数中直接进行初始化,而是通过一个专门的函数来实现对象的可重用性。然而,我不确定当Dispose被调用时会发生什么。如果GC调用它,对对象的引用无论如何都会丢失,所以不用担心。如果显式调用它,简单地调用Initialize并将类作为GC后的新对象处理是否有任何缺点。SupressFinalize被调用了吗?哈哈,我肯定我可以用更简单的方式问这个问题。

public abstract class Thread: System.IDisposable
{
    protected bool Disposed { get; set; }
    protected bool Terminate { get; private set; }
    public bool IsRunning { get; private set; }
    private System.Threading.Thread ThreadObject { get; set; }
    public Thread ()
    {
        this.Initialize();
    }
    ~Thread ()
    {
        this.Dispose(false);
    }
    public virtual void Initialize ()
    {
        this.Stop();
        this.Disposed = false;
        this.Terminate = true;
        this.IsRunning = false;
        this.ThreadObject = null;
    }
    //====================================================================================================
    // Functions: Thread
    //====================================================================================================
    public void Start ()
    {
        if (!this.IsRunning)
        {
            this.IsRunning = true;
            this.Terminate = false;
            this.ThreadObject = new System.Threading.Thread(new System.Threading.ThreadStart(this.Process));
            this.ThreadObject.Start();
        }
    }
    /// <summary>
    /// Override this method to do thread processing.
    /// [this.Terminate] will be set to indicate that Stop has been called.
    /// </summary>
    /// <param name="template"></param>
    protected abstract void Process ();
    public void Stop (System.TimeSpan timeout)
    {
        if (this.IsRunning)
        {
            this.Terminate = true;
            try
            {
                if (timeout.TotalMilliseconds > 1D)
                {
                    this.ThreadObject.Join(timeout);
                }
                else
                {
                    this.ThreadObject.Join();
                }
            }
            catch
            {
                try
                {
                    this.ThreadObject.Abort();
                }
                catch
                {
                }
            }
            this.ThreadObject = null;
            this.IsRunning = false;
        }
    }
    //====================================================================================================
    // Interface Implementation: System.IDisposable
    //====================================================================================================
    public void Dispose ()
    {
        this.Dispose(true);
        System.GC.SuppressFinalize(this);
    }
    protected virtual void Dispose (bool disposing)
    {
        if (!this.Disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                this.Stop(System.TimeSpan.FromSeconds(1));
            }
            // Dispose unmanaged resources here.
            // Note disposing has been done.
            this.Disposed = true;
        }
    }
}

自定义初始化函数与IDisposable

GC永远不会调用Dispose,这取决于消费代码。然而,GC会调用终结器。这在最佳实践IDisposable实现中用于仅清理非托管代码。

如果Dispose在结束器的上下文之外使用,那么GC就不需要调用结束器,因此使用SuppressFinalize作为优化来防止它发生两次。

如果对象被重用,这将导致一个问题。从技术上讲,您可以在初始化时重新注册终结器,但这需要确保线程安全。通常的做法是,对象在成为Disposed之后不被重用,而且通常Dispose方法应该只执行一次。在我看来,初始化方法和对象重用给模式带来了复杂性,使其偏离了预期目的。

不能以这种方式重新激活已处理对象没有技术上的原因,不过我不会这样做,因为这违反了最少意外原则(大多数一次性对象都使用一次)。

如果你真的想这样做,我会避免使用终结器,这意味着你的IDisposable类不能直接拥有任何非托管资源。您可以通过将类使用的任何非托管资源包装在托管包装器中来实现这一点(例如,查看SafeHandle类的示例)。

我不喜欢你的线程处理的所有精确细节,但是如果你要有一个类,其中每个实例拥有一个线程,你应该提供一个Dispose方法,以确保实例的线程以有序的方式死亡。

如果您希望允许线程在对象被放弃时也能被清理,您可能必须创建一个包装器对象,外部应用程序持有该对象的引用,而您的线程没有。该包装器对象的Finalize()方法应该以这样一种方式推动线程,使其死亡。线程可以简单地每隔几秒钟轮询一个标志,看看它是否应该退出,或者可以有一个更复杂的终止策略。

我很困惑,虽然,为什么Initialize调用Stop()?我希望它调用Start()

代码中使用了错误的语言模式应用程序示例。我清楚地看到c#代码作者有c++背景。遗憾的是,c++的编码技术并不适用于c#语言。

最好不允许对象进入垃圾收集器(GC),而只是在其他地方引用它,就像在Singleton模式中一样,而不是试图复活被处置的对象,或者在不允许完全控制垃圾收集器和内存管理的语言中使用Dispose模式,就像在c++中一样。

简单地说,你不应该在c#中使用c++的习惯用法,但是技巧和技巧是:

c++中的

接口而不是纯虚函数;用接口继承代替c++中的多类继承;c++中没有内存管理(使用弱引用)而不是完全控制对象生命周期