Мне нужно вызвать Dispose() для управляемых объектов?

Не могу поверить, что я все еще запутался в этом, но, как бы то ни было, давай наконец подделать его:

У меня есть класс, который переопределяет OnPaint для рисования. Чтобы ускорить работу, я создаю в конструкторе ручки, кисти и т.д., Поэтому в OnPaint не нужно создавать и удалять их.

Теперь я уверен, что я всегда распоряжаюсь такими объектами, но у меня такое чувство, что мне не нужно, потому что, несмотря на то, что они реализуют IDisposable, они управляются объектами.

Правильно ли это?


Спасибо за все ответы, проблема, безусловно, была прибита.
Я рад, что был бдительным в том, что всегда использовал "использование", так что мне не нужно проходить проверку кода. Я просто хотел быть ясным, что я не был бессмысленным пользователем.

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

Ответы

Ответ 1

Это неверно. Вам нужно реализовать объекты, которые реализуют IDisposable. Вот почему они реализуют IDisposable - для указания того, что они обертывают (прямо или косвенно) неуправляемые ресурсы.

В этом случае неуправляемый ресурс является дескриптором GDI, и если вы не удалите их, когда вы на самом деле с ними работаете, вы будете терять эти дескрипторы. Теперь у этих конкретных объектов есть финализаторы, которые вызовут освобождение ресурсов, когда GC начнет работать, но вы не знаете, когда это произойдет. Это может быть через 10 секунд, это может быть через 10 дней; если ваше приложение не создает достаточного давления в памяти, чтобы заставить GC вскочить и запустить финализаторы на этих кистях, ручках/шрифтах и ​​т.д., вы можете закончить голодание ОС ресурсов GDI до того, как GC когда-нибудь поймет, что происходит.

Кроме того, у вас нет гарантии, что каждая неуправляемая оболочка фактически реализует финализатор. Сама .NET Framework довольно последовательна в том смысле, что классы, реализующие IDisposable реализуют ее с помощью правильного шаблона, но это вполне возможно для некоторых другой класс, чтобы иметь сломанную реализацию, которая не включает финализатор и, следовательно, не очищается должным образом, если только Dispose не будет явно открыто на нем. В общем, цель IDisposable заключается в том, что вы не должны знать или заботиться о конкретных деталях реализации; скорее, если оно одноразовое, то вы избавитесь от него, период.

Мораль истории: всегда располагайте объекты IDisposable. Если ваш класс "владеет" объектами, которые IDisposable, тогда он должен реализовать IDisposable сам.

Ответ 2

Вам нужно их уничтожить.

Управляемый объект самостоятельно управляет своей памятью. Но память - это не единственный ресурс, который использует объект. Dispose() предназначен для освобождения других ресурсов.

Ответ 3

В вашем подходе есть выраженная ирония. Предварительно создавая ручки/кисти, вы точно создаете проблему, которую Dispose() пытается решить. Эти объекты GDI будут работать дольше, точно так же, как если бы вы не вызывали Dispose(). На самом деле хуже, они будут, по крайней мере, до тех пор, пока форма не будет закрыта.

Они, вероятно, достаточно долго, чтобы получить повышение до поколения №2. Сборщик мусора очень часто не делает сборку # 2, теперь более важно вызвать Dispose() на них. Сделайте это, переместив метод Dispose() формы из файла Designer.cs в файл form.cs и добавьте вызовы Dispose.

Но сделайте это правильно. Ручки и кисти - очень дешевые предметы. Создайте их, когда они вам понадобятся, в событии Paint. И используйте инструкцию using, чтобы они сразу же разобрались. Используйте класс "Секундомер", чтобы заверить себя, что это фактически не приводит к замедлению.

Ответ 4

Я написал компонент диаграммы GDI +, который использовал много ручек и кистей. Я создал их и разместил их в блоке кода, который выполнял чертеж, и производительность никогда не была проблемой. Лучше, чтобы потом иметь длинную ручку, висящую в ОС ИМХО.

Ответ 5

Профилировали ли вы это, чтобы увидеть, действительно ли создание и удаление этих объектов является проблемой? Я не думаю, что это так.

Вы делаете вещи намного проще для себя и, конечно, меньше подвержены ошибкам, просто следуя шаблону create-in-a-using-block.

Если вы хотите их создать один раз, затем также реализуйте IDisposable на своем собственном классе и выполните итерацию Dispose поверх принадлежащих вам объектов. Нет необходимости в деструкторе (финализатор).

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

Ответ 6

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

Ответ 7

Вам действительно нужно найти документацию для кистей, ручек и т.д.

Если они не используют неуправляемые ресурсы, вам может не потребоваться вызывать Dispose. Но использование /Dispose шаблона иногда "неправильно используется". В качестве примера рассмотрим структуру ASP.NET MVC. Здесь вы можете написать что-то вроде:

using(Html.BeginForm(...)){
  ///HTML input fields etc.
}

Когда вызывается Html.BeginForm(...), выдается тег FORM. Когда инструкция use завершается, на объект, возвращенный из Html.BeginForm(...), вызывается Dispose. Вызов Dispose вызывает удаление тега FORM. Таким образом, компилятор фактически обеспечит сопряжение тегов FORM, поэтому вы не забудете закрывающий тег.

Ответ 8

Нет, Pen и Brush es - это не полностью управляемые объекты.

Они содержат дескриптор неуправляемого ресурса, то есть соответствующий объект GDI в базовой графической системе. (Не определенно о точной терминологии здесь...)

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

Ответ 9

Нет, это неправильно. Я согласен с Аароновом.

Кроме того, в середине 2003 года Microsoft рекомендует, чтобы Don Box представила, что каждый разработчик .Net должен распоряжаться своими собственными объектами, независимо от того, управляется или неуправляем, поскольку это повышает производительность кода на что-либо до 20%. Если все сделано правильно, это может стать существенным улучшением производительности. Таким образом, это ключевой навык, который должен знать и использовать каждый разработчик .net.

Ответ 10

Другие ссылаются на "использование" блоков для объектов GDI - здесь пример кода:

using( var bm = new Bitmap() )
using( var brush = new Brush() )
{

   // code that uses the GDI objects goes here
   ...

} // objects are automatically disposed here, even if there an exception

Обратите внимание, что вы можете иметь столько "используемых" строк, сколько хотите для одного блока кода.

Я думаю, что это хороший, чистый способ борьбы с одноразовыми объектами.

Ответ 11

Хотя вы спрашивали о ручках и кистях, Font - это класс с некоторыми нечетными причудами. В частности, если вы создаете шрифт с целью установки свойства Font элемента управления, он остается ответственным за удаление этого шрифта - право собственности не переходит к элементу управления, но эта ответственность может быть выполнена путем удаления шрифта в в любое время - даже после создания шрифта, прежде чем назначать его элементу управления. Кажется, Font представляет собой комбинацию управляемого объекта информации и неуправляемого ресурса GDI, и для некоторых целей требуется только первая. Странный дизайн - Шрифт должен быть двух классов.