Должен ли я создавать новые запросы Pens/Brushes для Paint или хранить их на протяжении всего жизненного цикла приложения?

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

using(var pen = new Pen(this.ForeColor))
{
    // Paint for this object.
}

Я читал противоречивые ответы, что это должно быть сделано для приложения, которое постоянно рисует одно и то же (может быть, просто изменено, перемещено и т.д.). Должен ли я хранить объект Pen/Brush с объектом, а затем удалять их все, когда приложение удаляется, или они достаточно эффективны для создания/размещения для каждого вызова краски (помня, что это приложение с интенсивной графикой).

РЕДАКТИРОВАТЬ. Уже есть два ответа, которые имеют противоречивые ответы, и именно здесь я не уверен, чтобы сделать переключатель. Кто-нибудь имеет какие-либо статистические данные о различиях?

Ответы

Ответ 1

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

Например, если вы хотите один из стандартных цветов Pens, вы можете сделать это:

var pen = Pens.Red;

Аналогичным образом вы можете сделать то же самое с Brushes, если вы просто хотите стандартные цвета сплошной кисти:

var brush = Brushes.Red

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

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

EDIT:

Чтобы создать и избавиться от массива из 100 000 новых ручек, потребовалось примерно полсекунды на моей старой старой машине XP, запуская тестовое приложение в режиме отладки.

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

Ответ 2

Вы узнаете только о влиянии производительности на тестирование в своем конкретном приложении, но структура, похоже, не имеет проблемы с сохранением нескольких ручек для жизни приложения. При первом вызове Pens.Black он создает черную ручку и кэширует ее. Вы возвращаете тот же объект для будущих вызовов, и он никогда не был явно удален (Pens.Black.Dispose() фактически генерирует исключение). Тем не менее, вы не хотите слепо создавать ручки и оставлять их доступными, когда приложение заканчивается, потому что вы будете пропускать неуправляемую память. Пара опций spring учитывать в зависимости от шаблона использования в вашем приложении.

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

Если вы используете относительно немного разных цветов, но многие объекты используют каждый цвет, вы можете не захотеть, чтобы каждый объект удерживался на собственной ручке. Создайте класс кеша, который хранит Dictionary<Color,Pen> и передает их через PenCache.GetPen(ForeColor). Как и при использовании Pens.Black, вы можете забыть об утилизации. Проблема возникает, если вы кратко используете цвет, а затем не нуждаетесь в нем снова. Пен получил кеширование, так что вы застряли с ним в памяти навсегда. Вместо этого вы можете сохранить Dictionary<Color,WeakReference<Pen>>, позволяя кэшированным ручкам в конечном итоге собираться мусор, если они больше не нужны.

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

Ответ 3

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

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

Ответ 4

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