2015-05-27 4 views
7

У меня есть некоторый код в приложении WPF, который выглядит следующим образом:Вызов BeginInvoke из деструктора

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 начнет работать в потоке пользовательского интерфейса. Похоже, что он работает. Что здесь происходит? Это безопасно?

+0

более интересный материал о финализаторов проверить [Когда все, что вы знаете, это неправильно, часть два] (http://ericlippert.com/2015/05/21/when-everything-you-know-is-wrong-part-two/) – Default

+0

Это воскрешение объекта. Я никогда раньше этого не видел. Вероятно, ваш TextBox не должен * иметь * финализатор (что вы пытаетесь сделать?). – usr

+0

Помимо плохой идеи, я не вижу в этом ничего хорошего ... –

ответ

4

Похоже, что в этом случае объект будет уничтожен до того, как делегата в BeginInvoke запускает в потоке пользовательского интерфейса

финализатор очередь работать в цикл обработки сообщений UI. Объект может завершить свой метод finalizer до, фактический делегат получает вызов в потоке пользовательского интерфейса, но это не имеет значения, поскольку делегат получает очередь в очереди.

Что здесь происходит?

Вы загружаете работу в пользовательский интерфейс из финализатора.

Это безопасно?

Safe - это широкий термин. Я бы сделал это? Точно нет. Похоже, странно, что вы вызываете манипулирование элементами пользовательского интерфейса из финализатора, особенно учитывая, что это элемент управления TextBox. Я предлагаю вам получить полное представление о том, что работает finalizer guarantees и не гарантирует. Во-первых, запуск финализатора не означает, что объект сразу очищается в памяти.

Я также предлагаю читать сообщения @EricLippert: Почему все, что вы знаете, не так, Part1 & Part2

+0

Это невозможно, потому что член класса уже был собран. Мы знаем это, потому что к нему обращаются к действительной управляемой ссылке, поэтому GC не позволяет * ее собирать. Если он обращается к любому из * неизмененных * ресурсов, которые он уже убрал в качестве части своего распоряжения, это может вызвать проблемы. – Servy

+0

@Servy Почему-то я думал, что однажды в f-достижимой очереди он считается мертвым (а не корнем). Я удалил ненужную часть. –

+0

На самом деле наоборот. Тот факт, что он находится в freachable queue, означает, что он очень живой. Он потеряет автоматическую регистрацию для завершения, хотя, если метод, отправленный BeginInvoke, завершает восстановление объекта, ему может потребоваться перерегистрация для завершения. Основная проблема заключается в том, что однажды в завершении вы потеряли всякое чувство *, когда это произойдет. Если приложение срывается, * почему * вы ставите в очередь больше работы для диспетчера? ** Это, безусловно, неправильный способ сделать то, что он делает! ** –

3

Когда вы вызываете BeginInvoke, вы добавляете делегата в очередь диспетчера, и этот делегат будет указывать на объект, имеющий ссылку на объект, на который был вызван Dispose. Поскольку существует ссылка на объект, доступный через корневую переменную, этот объект не подлежит сбору.

Теперь это будет очень смущать других, используя этот код, поэтому вы должны стараться избегать «реанимации» объектов, которые уже были финализированы, если это вообще возможно.

+0

Это зависит от того, что он делает внутри функции там ... это может не реанимировать объект ... –

+0

@AK_ Это реанимирует объект по крайней мере до тех пор, пока действие не завершит выполнение, и поскольку этот метод пытается обработать объект как действительный объект, после его размещения я бы рассмотрел эту форму реанимации. Конечно, это по своей сути фраза, которая не является технической, и поэтому не так точна. Точный оператор, как было сказано ранее, заключается в том, что объект не может быть собран, пока этот делегат держит (косвенную) ссылку на объект. – Servy

+0

Почему делегат должен иметь ссылку на объект? –

Смежные вопросы