C#析构函数超出范围后不调用

时间:2012-06-11 17:50:02

标签: c# scope destructor

我在退出范围后遇到了析构函数的问题(它正在调用但是在一段时间之后需要在表单上进行操作,例如更改单选按钮),也许我的代码中存在错误。看看:

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
            EventLogger.Print += delegate(string output)
            { if (!textBox1.IsDisposed) this.Invoke(new MethodInvoker(() => textBox1.AppendText(output + Environment.NewLine)), null); };
        }

        private void button1_Click(object sender, EventArgs e)
        {
            TestClass test = new TestClass();
        }
    }
    public static class EventLogger
    {
        public delegate void EventHandler(string output);
        public static event EventHandler Print;
        public static void AddLog(String TextEvent)
        {
            Print(TextEvent);
        }
    }
    public class TestClass
    {
        public TestClass()
        {
            EventLogger.AddLog("TestClass()");
        }
        ~TestClass()
        {
            EventLogger.AddLog("~TestClass()");
        }
    }

}

4 个答案:

答案 0 :(得分:9)

是的,因为这不是C ++。在对象离开其声明范围后,不保证立即调用终结器(不是在C ++中的析构函数),当GC决定进入并在您之后清理时调用它。

我可以问你为什么要使用终结器吗?您是否维护对非托管资源的引用,这些资源需要尽可能确定地解除分配(如果是这样,请在IDisposable接口上阅读)? C#终结器的用例很少,实现起来并不常见。

答案 1 :(得分:3)

C#不是C ++。 Destructors don't run synchronously

您的代码中没有错误,但看起来您可能需要为您的类实现“IDisposable模式”,以便为调用者提供一种方法来保证同步执行某些对象的破坏。

答案 2 :(得分:2)

对于我们这些对C ++模式更熟悉的人来说,查看IDisposable接口的文档很有用:

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

不幸的是,我刚尝试过它并没有按照我的意愿行事。我使用自动对象来保存GUI游标的当前状态,切换到等待游标并在对象超出范围时恢复原始游标。 IDisposable接口确实导致光标被恢复但不是立即 - 因此等待光标显示的时间太长。太糟糕了,因为这是一个非常有用的模式。

答案 3 :(得分:0)

终结器不能在超出范围后立即调用。在对象被垃圾收集时调用它,在超出范围后可以是几毫秒到几天。

终结器不适用于此类代码。它仅用于资源清理。

你不能强迫它在超出范围后立即做某事,但你可以在超出范围之前立即告诉它,使用Close()或类似的方法来表示对象已完成使用

例如:

private void button1_Click(object sender, EventArgs e)
{
    TestClass test = new TestClass();
    // do stuff
    test.Close();
}

注意:您可以按照建议实现IDisposable,但这种用法并不完全符合IDisposable的预期用途,所以尽管它可行,但它有点hackish。