Почему шрифт неизменен?

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

Почему шрифт является неизменным ссылочным типом?

Ответ 1

Это упрощает использование системы рендеринга.

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

Кроме того, я не согласен с термином "Бедствие программисту". Сделав Font неизменным, он делает более очевидным, что происходит, когда пользователь создает объект Font. Если вы хотите новый шрифт, вам нужно создать новый объект Font, который, в свою очередь, создаст новые собственные ресурсы шрифтов. Создание неизменного шрифта делает его более понятным, что происходит - вы с меньшей вероятностью создадите проблему с производительностью случайно.

Если шрифт изменен, было бы менее очевидно, что вы неоднократно создавали дескрипторы при изменении свойств шрифта.

Ответ 2

Хорошо, задайте себе несколько вопросов.

Во-первых, шрифт логически изменчив, например, список продуктов или непреложная вещь, например номер? Если вы моделируете список продуктов в программе, имеет смысл сделать его изменчивым, потому что вы обычно думаете о том, что один список продуктов, содержимое которого изменяется по мере того, как вы заканчиваете или покупаете определенные предметы. Но числа, которые вы обычно моделируете как неизменные - число 12 - это число 12, теперь и навсегда.

Я думаю, что "Helvetica 12 point bold" является фиксированной, неизменной, как число, а не тем, что я могу изменить.

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

Поскольку я считаю шрифты неизменными и упоминаемыми, а не как изменчивые и скопированные по значению, я лично моделировал бы шрифты как неизменные ссылочные типы. Возможно, ваши интуиции о шрифтах отличаются от моих.

Ответ 3

Они не являются структурами, потому что им нужно иметь финализаторы для обертывания базовых объектов и обеспечения разумной реализации IDisposable. Что произойдет, если вы Dispose() свою собственную копию struct? Вы каждый раз клонируете ручку?

На GC очень мало внимания...

Он также позволяет безопасно использовать Font, не беспокоясь об этом, изменяя половину операции: -p

Ответ 4

Я не согласен, что это расстраивает программиста. В BCL существует множество неизменных типов, которые ежедневно используются программистами и не вызывают никаких проблем. Например, System.String.

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

Наконец, шрифт на самом деле не является непреложным классом в строгом смысле слова. Он реализует IDisposable и в методе Dispose сбрасывает основной объект.

Ответ 5

Вы можете утверждать, что это расстраивает разработчика. Но вы также можете сделать тот же аргумент в обратном случае.

Например:

// Let me just set the button to the same font as the textbox...
button.Font = textBox.Font;

// ...except that I want the button font to be bold.
button.Font.Bold = true;

В приведенном выше коде была бы выбрана кнопка и шрифт текстового поля, если Font изменен, что противоречит ожиданиям разработчиков.

Ответ 6

Шрифт - это плохо спроектированный объект, который нарушает принцип единой ответственности, и трудности, которые вы приводите, вытекают из этого. Проблема с Font заключается в том, что она включает в себя две вещи: (1) описание того, как должен быть нарисован шрифт, и (2) объект шрифта GDI для шрифта с этими свойствами. Первый тип может быть изменен без последствий, в то время как последний тип mutable будет создавать всевозможные проблемы.

В частности, рассмотрим вопрос о том, как следует отслеживать право собственности на типичное свойство шрифта (например, Button) Font? Если кто-то иногда меняет шрифты, связанные с элементами управления, нужно создать отдельный объект Font для каждого элемента управления и утилизировать его при смене управляющего шрифта на что-то еще или сохранить список всех разных шрифтов, которые используются таким образом чтобы избежать создания избыточного количества идентичных объектов шрифта или что?

Если существовала структура FontDescription (которая была изменчивой, а не IDisposable), и такие вещи, как Control.Font, имели тип FontDescription (или, еще лучше, Control разоблачил метод SetFont с параметром типа FontDescription), вышеупомянутый вопрос может быть ответил довольно просто. Как бы то ни было, наиболее эффективным подходом для установки шрифта элемента управления является создание нового объекта шрифта (если у него еще нет подходящего), немедленно удалите его, а затем выполните задание. Часть "Описание шрифта" шрифта остается квазидействующей даже после удаления, и все, что действительно необходимо для свойства Control.Font.