Почему шрифт неизменен?
Шрифт, являющийся неизменным, вызывает проблемы как программиста, так и 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.