2013-03-20 4 views
1

Есть ли способ отменить удаление из метода Dispose, другими словами НЕ УДАЛИТЬ A при вызове A.Dispose().Отменить dispose inside Dispose method

Обновление Я не очень хорошо объяснял, потому что я не мог придумать, как это сделать. У меня есть класс, который отображает индикатор выполнения (marquee) во всплывающем окне, которое выполняется в отдельном потоке. Когда прогресс всплывающее окно создается, контроллер, как одноразовый объект возвращается, так что мы можем сделать что-то вроде этого:

using (var progress = Dialogs.ShowProgress("Please wait...")) 
{ 
    // do lots of stuff here 
    progress.UpdateStatus("Please wait some more..."); 
    // do more stuff 
} 

при использовании выходов блока, окно прогресса закрыт и разрушен.

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

Update Хорошо, что я сделал, чтобы создать новый объект IDisposable с каждым Dialogs.ShowProgress() вызова, а также прилагается исходный объект контроллера к нему. Эти объекты удаляются, когда они будут сделаны, и контроллер только удаляется, когда это единственный объект, оставшийся в распоряжении.

+3

Почему в мире вы хотели бы сделать это? В основном вы спрашиваете: «У меня есть этот контракт, в котором говорится, что я должен делать X, но я не хочу ... как мне это избежать?» – JerKimball

+2

Я чувствую здесь злоупотребление картой. Если для всей платформы .NET нет необходимости отменять вызов Dispose(), как вы думаете, вам действительно нужно? –

+1

Вы вводите в заблуждение метод 'Dispose', который является соглашением (широко используемым в .NET Framework, но не языком, просто соглашением), с _finalizer_ (который имеет другой синтаксис) и _still_ вы можете ' t отменить финализатор (что не имеет смысла) ... путь к _ "cancel" _ 'Dispose' просто ... не вызывает' Dispose'. – Jcl

ответ

1

Несомненно. Просто не делайте, что бы вы сделали, чтобы уничтожить объект. Вам не нужно активно делать что-то особенное.

Будьте осторожны; когда кто-то распоряжается объектом, он ожидает, что он фактически избавится от неуправляемых ресурсов, вместо того, чтобы игнорировать вас и удерживать их в любом случае.

+1

Этот тип кода заставляет меня хотеть отправиться на охоту с помощью ClueBat ... – JerKimball

+0

Каким образом это не отвечает на вопрос именно так, как было задано? – Servy

+0

О, я тебя вообще не стучаю, @Servy - вопрос OP был моей мишенью, извините :) – JerKimball

1

Я был бы осторожен в этом. Если вы отмените удаление метода в конце используемого блока, то вы потеряли ссылку на этот объект, и у вас никогда не будет возможности снова избавиться от его содержимого, что означает, что вы можете утечка ресурсов, не осторожны. В частности, я бы сделал это сам, только если метод dispose выпустил ссылки на большие объекты, которые я не хотел, чтобы сбор мусора сразу по какой-то причине. Я бы не сделал этого, чтобы пропустить освобождение дескрипторов файлов, подключений к базе данных, сетевых сокетов или чего-либо еще, что невозможно собрать мусором.

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

Если вы абсолютно уверены, что у вас есть граничное условие, где вам нужно пропустить утилизации что-то, вот один из способов сделать это:

public void Dispose() 
{ 
    if(condition) 
    { 
     // do disposing stuff 
    } 
} 
+0

+1 для объяснения, почему это плохая идея для этого. –

+1

все еще ужасная идея, несмотря на объяснение. 'использование' не поддерживает * условно одноразовые объекты * –

+1

@StenPetrov'! condition' сам по себе является типом условий, поэтому ваш код точно такой же. – Servy

4

Как уже сказал, что это плохая идея реализовать IDisposable таким образом, который не может реально распоряжаться. Вот альтернативный способ осуществить то, что вы пытаетесь сделать:

interface IMaybeDisposable 
{ 
    bool TryDispose(); //return false if dispose was canceled 
} 

Вы можете использовать его как:

IMaybeDisposable maybe = //something 
try 
{ 
    // do something with maybe 
} 
finally 
{ 
    if (maybe.TryDispose()) 
     // yay, it disposed! 
    else 
     // hm, it didn't dispose; do something else 
} 
+2

+1 Это действительно надежное решение, позволяющее избежать использования вашего объекта в 'using' –

+3

+1. Все еще сомнительно, если кому-то это действительно понадобится, но, по крайней мере, этот интерфейс четко сообщает, что происходит. –

+1

@ DanielHilgarth Я согласен. Нужно ли это указывать на плохой дизайн где-то в другом месте? –

1

Требуемое пост-условием Dispose является то, что клиентский код должен быть в состоянии отказаться от всех ссылок на объект, не вызывая никакой необходимой очистки для незавершенности. Если это условие применяется до вызова Dispose, то метод Dispose может на законных основаниях ничего не делать.Если это условие не применяется, Dispose должно сделать это и не может законно возвращаться, если или пока оно не будет [обратите внимание, что Dispose не должен фактически выполнять очистку, если он вызывает цепочку событий, через которые произойдет очистка в более позднее время]. Ничто в контракте для интерфейса Dispose не позволяет ему иногда оставлять объекты в состоянии, требующем дальнейшей очистки, если у него нет оснований полагать, что очистка произойдет с помощью некоторых других средств.

0

На основе вашего обновления, я хотел бы сделать что-то вроде этого:

public void DoStuff() 
{ 
    DoPrepWork(); 
    using(var controller = TheMethodYouWroteThatShouldReturnAController()) 
    { 
     DoStuffOverControllerLifetime(); 
    } 
} 
+0

Это хорошо, но материал, создающий вложенные приложения, можно также назвать в другом месте, где они затем станут создателями исходного контроллера. Конечно, я мог бы также не понимать ваш ответ. – bixarrio