.Net - правильно утилизировать дочерний объект

Из анализа кода (Visual studio) я получил это предупреждение:

Предупреждение 2 CA2000: Microsoft.Reliability: ... Вызовите System.IDisposable.Dispose для объекта 'l' до того, как все ссылки на него будут вне области действия...

Итак, я изменил код:

Dim l As LiteralControl = New LiteralControl
AddHandler l.DataBinding, AddressOf OnDataBinding
container.Controls.Add(l)

to

Dim l As LiteralControl = Nothing
Try
    l = New LiteralControl
    AddHandler l.DataBinding, AddressOf OnDataBinding
    container.Controls.Add(l)
Finally
    If Not l Is Nothing Then
        l.Dispose()
    End If
End Try

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

РЕДАКТИРОВАТЬ

Обратите внимание, что код взят с веб-страницы Microsoft: http://msdn.microsoft.com/en-us/library/system.web.ui.itemplate.instantiatein.aspx


person Melursus    schedule 19.08.2010    source источник
comment
1 — ужасное имя переменной.   -  person SLaks    schedule 19.08.2010
comment
Это только пример. Я не поставил настоящий код   -  person Melursus    schedule 19.08.2010


Ответы (1)


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

вместо удаления на finally (что уничтожает ваш объект все время), вам нужно изменить это на catch и удалить в поймать, а затем повторно сгенерировать исключение.

Это избавит вас от предупреждения и даст вам правильную обработку dispose. Да, в данном конкретном случае это нереально, но возможно.

person John Gardner    schedule 19.08.2010
comment
В качестве альтернативы вы можете сохранить finally, но обнулить переменную в конце try. Та же разница, хотя, и ваше предложение, вероятно, яснее. Я просто предлагаю это как нечто более близкое к оригиналу. - person Steven Sudit; 19.08.2010
comment
@Steven: я думаю, что обнуление переменной в конце попытки лучше, чем перехват. Перехват и повторная выдача исключения иногда могут испортить трассировку стека; кроме того, если возникает исключение, которое не будет обработано, перехват и повторное генерирование приведет к тому, что очевидной точкой ошибки будет повторное генерирование, а не место, где изначально возникло исключение. - person supercat; 06.01.2011
comment
@supercat: создание нового исключения приведет к потере трассировки стека, если только вы не используете исходное исключение в качестве внутреннего исключения нового. Насколько мне известно, повторное генерирование его с помощью throw; не повредит трассировке стека и не сделает его похожим на исключение, возникшее в блоке catch. - person Steven Sudit; 07.01.2011
comment
@Steven Sudit: поймать и повторно бросить, даже используя простой бросок, немного испортит трассировку стека, по крайней мере, по состоянию на vs2010. Если метод CatchAndThrow вызывает Foo из строки 23, а Foo генерирует исключение, которое перехватывается, а затем повторно генерируется в строке 57, трассировка стека будет включать информацию о том, что произошло внутри Foo, но будет указывать, что исключение возникло через строку 57 CatchAndThrow, а не чем строка 23. - person supercat; 07.01.2011
comment
@supercat: вы правы, но номер строки отображается только в том случае, если доступна PDB; в противном случае он показывает только метод. Поскольку я забочусь о трассировке стека только тогда, когда код работает в рабочей среде, и я обычно не отправляю PDB, для меня это не проблема. - person Steven Sudit; 07.01.2011