简体   繁体   English

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

[英]C# Destructor not calling after out of scope

I have problem with destructor after going out of scope(it is calling but after some time and need to make an action on form, for example change radio button), maybe there's mistake in my code.超出范围后,析构函数出现问题(它正在调用,但经过一段时间后需要对表单进行操作,例如更改单选按钮),也许我的代码中有错误。 Take a look:看一看:

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()");
        }
    }

}

Right, because this isn't C++.是的,因为这不是 C++。 The finalizer (not destructor as in C++) is not guaranteed to be called immediately after an object has left its declaring scope, it is called when the GC decides to swoop in and clean up after you.终结器(不是 C++ 中的析构函数)不能保证在对象离开其声明范围后立即调用,它会在 GC 决定在您之后猛扑并清理时调用。

May I ask why you are using a finalizer to begin with?请问你为什么要使用终结器开始? Are you maintaining references to unmanaged resources which need to be deallocated as deterministically as possible (if so, read up on the IDisposable interface)?您是否维护对需要尽可能确定性地解除分配的非托管资源的引用(如果是这样,请阅读 IDisposable 接口)? The use cases for C# finalizers are few and far between, it's not common to implement them. C#终结器的用例很少,实现它们并不常见。

C# is not C++. C# 不是 C++。 Destructors don't run synchronously .析构函数不会同步运行

There is no bugs in your code as is, but it looks like you may need to implement "IDisposable pattern" for your class to provide a way for caller to guaranty that some destruction of your object is executed synchronously.您的代码中没有错误,但看起来您可能需要为您的类实现“IDisposable 模式”,以便为调用者提供一种方法来保证您的对象的某些销毁是同步执行的。

For those of us who are more comfortable with the C++ pattern it's useful to check out the docs for the IDisposable interface:对于我们这些对 C++ 模式更熟悉的人,查看 IDisposable 接口的文档很有用:

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

Unfortunately I've just tried it and it's not working as I'd like.不幸的是,我刚刚尝试过它并没有像我想要的那样工作。 I used an automatic object to save the current state of the GUI cursor, switch to the wait cursor and restore the original cursor as the object goes out of scope.我使用了一个自动对象来保存 GUI 光标的当前状态,切换到等待光标并在对象超出范围时恢复原始光标。 The IDisposable interface does result in the cursor being restored but not immediately - so the Wait Cursor is showing for too long. IDisposable 接口确实会导致光标恢复,但不会立即恢复 - 因此等待光标显示时间过长。 Too bad because this is a very useful pattern.太糟糕了,因为这是一个非常有用的模式。

Update: The C# try/finally pattern is comfortable enough after a while:更新:一段时间后,C# try/finally 模式已经足够舒服了:

public void do_something_time_consuming()
{
   ShowBusyCursor cursor = new ShowBusyCursor();

   try
   {
      ...
      return;
   }
   finally
   {
      cursor.done();
   }
}

The finalizer is not designed to be called immediately after going out of scope.终结器不是设计为在超出范围后立即调用。 It is called when the object is garbage-collected, which be may anywhere from milliseconds to days after going out of scope.它在对象被垃圾收集时被调用,这可能是超出范围后几毫秒到几天的任何时间。

The finalizer is NOT meant for this kind of code.终结器不适用于此类代码。 It is only for resource cleanup.它仅用于资源清理。

You can't force it to do something immediately after going out of scope, but you can tell it to immediately before going out of scope, with a Close() or similar method to signal that the object is done being used.您不能在超出范围后立即强制它执行某些操作,但您可以在超出范围之前立即告诉它,使用Close()或类似方法来表示该对象已完成使用。

For example:例如:

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

Note: You could implement IDisposable , as has been suggested, but this use doesn't exactly fit the intended use of IDisposable , so although it would work, it's a bit hackish.注意:您可以按照建议的方式实现IDisposable ,但这种用法并不完全符合IDisposable的预期用途,因此虽然它可以工作,但有点不合时宜。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM