从析构函数调用 BeginInvoke

Calling BeginInvoke from a destructor

我在 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 线程上触发之前被销毁。它似乎正在工作。这里发生了什么?这样安全吗?

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

现在,这会让使用此代码的其他人感到非常困惑,因此您应该尽可能避免 "reanimating" 已经完成的对象。

It seems like in this case the object would be destroyed before the delegate in the BeginInvoke fires on the UI thread

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

What is happening here?

您正在将终结器中的工作排队到 UI。

Is this safe?

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

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