从析构函数中调用BeginInvoke

时间:2015-05-27 14:05:02

标签: c# .net wpf dispatcher

我在WPF应用程序中有一些代码如下:

public class MyTextBox : System.Windows.Controls.TextBox, IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        Dispatcher.BeginInvoke((Action) delegate
        {
            // do work on member variables on the UI thread.
        });
    }

    ~MyTextBox()
    {
        Dispose(false);
    }
}

dispose方法永远不会被显式调用,因此析构函数会调用它。看起来在这种情况下,对象将在BeginInvoke中的委托在UI线程上触发之前被销毁。它似乎工作了。这里发生了什么?这样安全吗?

2 个答案:

答案 0 :(得分:4)

  

在这种情况下,似乎对象会在之前被销毁   BeginInvoke中的委托在UI线程上触发

终结器队列工作到UI消息循环。在在UI线程上调用实际委托之前,该对象可能会完成运行其终结器方法,但这并不重要,因为委托无论如何都会排队。

  

这里发生了什么?

您正在从终结器排队工作到用户界面。

  

这样安全吗?

安全是一个广义的术语。我会这样做吗?当然不。您从终结器调用UI元素的操作看起来很奇怪,特别是考虑到这是一个TextBox控件。我建议你完全掌握运行finalizer guarantees并且不保证的内容。首先,运行终结器并不意味着对象会立即在内存中清理。

我还建议阅读@EricLippert帖子:为什么你知道的一切都是错的Part1& Part2

答案 1 :(得分:3)

当您调用BeginInvoke时,您需要将一个委托添加到调度程序中的队列,该委托将指向一个对象,该对象具有Dispose对象的引用被叫了。由于存在对可通过有根变量访问的对象的引用,因此该对象不符合收集条件。

现在,这对使用此代码的其他人来说会非常混乱,因此您应该尽量避免"重新生成"已经完成的对象,如果可能的话。