Как обращаться с одноразовыми предметами, на которые у нас нет ссылок? - PullRequest
7 голосов
/ 08 октября 2009

Если у вас есть кисть и ручка, как в:

Brush b = new SolidBrush(color);
Pen p = new Pen(b);

и распоряжаться ими так:

b.Dispose();
p.Dispose();

Как бы вы избавились от этого, если бы это было:

Pen p = CreatePenFromColor(color) что бы создать кисть и ручку для вас? Я не могу избавиться от кисти внутри этого метода, верно?

Этот метод нельзя использовать с одноразовыми предметами?

РЕДАКТИРОВАТЬ: Что я имею в виду, как вы располагаете кисть?

Ответы [ 5 ]

9 голосов
/ 08 октября 2009

Задачей метода CreatePenFromColor является удаление экземпляра Brush. С первого взгляда это неочевидно, но если вы углубитесь в реализацию класса Pen, то увидите, что он не поддерживает переданный экземпляр Brush. Вместо этого он просто использует его для вычисления нескольких значений. Таким образом, нет никакой причины для экземпляра Brush жить за пределами вызова CreatePenFromColor, и метод должен избавляться от экземпляра.

6 голосов
/ 08 октября 2009

Вы все еще должны избавиться от него, когда закончите.

Например, вы можете назвать это так:

using (Pen p = CreatePenFromColor(color))
{
    // do something
}

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

[Редактировать] Теперь у меня возник вопрос - вы используете конструктор Pen (Brush b).

а. В этом случае кажется, что Pen не нужен экземпляр Brush после конструктора, поэтому ваш метод может выглядеть следующим образом:

public Pen CreatePenFromColor(Color c)
{
    using (Brush b = new SolidBrush(c))
    { return new Pen(b); }
}

б. Почему бы просто не использовать Ручка (цветной цвет) ?

public Pen CreatePenFromColor(Color c)
{
    return new Pen(c);
}

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

public class PenHelper : IDisposable
{
     private readonly Brush _brush;
     public PenHelper(Color color)
     {
         _brush = new SolidBrush(color);
     }

     public Pen CreatePen()
     {
         return new Pen(_brush);
     }

     public void Dispose()
     {
         _brush.Dispose();
     }
}

и затем используйте его так:

using (PenHelper penHelper = new PenHelper(Color.Black))
{
     using (Pen pen = penHelper.CreatePen())
     {
          // do stuff
     }
}

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

2 голосов
/ 08 октября 2009

У вашей проблемы нет общего решения.

В вашем конкретном примере это не проблема, потому что у Pen есть конструктор, который напрямую принимает Color.

Некоторые классы сами располагают свои параметры конструктора (особенно классы, связанные с Stream); проверьте каждый класс в Reflector.

Если возвращаемый класс наследует от Component, вы можете добавить обработчик к его событию Disposed.

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

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

1 голос
/ 02 декабря 2011

Одним из моих недостатков во многих связанных с графикой классах является то, что нет единого шаблона для решения таких проблем. Что действительно необходимо, так это средство реализации частичного подсчета ссылок. Не в стиле COM, где для передачи ссылок требуется постоянное увеличение количества ссылок, а в способе, с помощью которого, учитывая IDisposable графический объект, можно запросить другой экземпляр, который совместно использует тот же базовый ресурс. Сами ресурсы будут заключены в общий объект со счетчиком ссылок. Создание другого экземпляра ссылки будет увеличивать счетчик; вызов Dispose для ссылающегося экземпляра уменьшит его. Это позволит избежать 95% накладных расходов при подсчете ссылок при сохранении 99% выгоды.

0 голосов
/ 08 октября 2009

Когда метод передает экземпляр IDisposable, он одновременно передает ответственность за управление жизненным циклом.

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

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

...