11

字体不可变让程序员和 GC 都感到苦恼,因为您每次都需要创建一个新实例。

那么为什么 Font 是不可变的引用类型呢?

4

6 回答 6

28

它简化了渲染系统的使用。

如果框架允许 Font 是可变的,它就需要检测变化,并定期修改它的呈现方式。由于 Font 创建了本机资源,因此保持此不可变可防止系统担心必须在内部重复地重新创建句柄。

另外,我不同意“程序员的痛苦”。通过使 Font 不可变,用户创建 Font 对象时发生的事情变得更加明显。如果你想要一个新的 Font,你需要创建一个新的 Font 对象,这反过来又会创建新的原生字体资源。使 Font 不可变可以更清楚地了解正在发生的事情 - 您不太可能意外地产生性能问题。

如果 Font 是可变的,那么在更改 Font 属性时重复创建句柄就不太明显了。

于 2009-10-13T15:52:39.513 回答
14

好吧,问自己一些问题。

首先,字体在逻辑上是可变的东西,比如购物清单,还是不可变的东西,比如数字?如果您在程序中对购物清单进行建模,则使其可变是有意义的,因为您通常会考虑拥有一个购物清单,当您用完或购买特定物品时,其内容会发生变化。但是您通常将数字建模为不可变的数字——数字 12 是数字 12,现在和永远。

我认为“Helvetica 12 点粗体”是一个固定的、不可变的东西,就像一个数字,不是我可以改变的。

其次,字体在逻辑上更像是您可以复制的值,还是更像是您可以引用的单一事物?我不认为拥有 Helvetica 的“两个副本”。我想参考 Helvetica。而我认为数字有不同的副本用于不同的目的——当我的购物清单上有 12 件物品和钥匙圈上有 12 把钥匙时,我不认为这两个东西都是“指 12”。

由于我认为字体是不可变的和被引用的,而不是可变的和按值复制的,我个人会将字体建模为不可变的引用类型。也许您对字体的直觉与我的不同。

于 2009-10-13T15:55:49.587 回答
8

它们不是结构,因为它们需要终结器来包装底层对象并提供合理的IDisposable实现。如果Dispose()您拥有自己的 a 副本会struct怎样?你每次都克隆手柄吗?

对GC来说压力并不大...

它还允许Font安全地重复使用,而不必担心它在操作中途改变;-p

于 2009-10-13T15:53:50.253 回答
4

我不同意这让程序员感到苦恼。BCL 中有很多不可变的类型,程序员每天都在使用它们,不会引起任何问题。例如 System.String。

不可变的好处之一是您不必每次都创建一个新实例。您可以根据需要多次重复使用相同的字体类型,因为它不会改变。另一方面,如果它是可变的,则您需要每次都制作一个副本,以帮助确保没有其他人从您的手下更改它。

最后,Font 实际上并不是严格意义上的不可变类。它实现了 IDisposable 并在 Dispose 方法中拆除了底层的本机对象。

于 2009-10-13T15:55:14.900 回答
0

您可以争辩说它让开发人员感到苦恼。但是你也可以在相反的情况下提出同样的论点。

例如:

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

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

如果是可变的,上面的代码会将按钮和文本框的字体同时设置为粗体,Font这与开发人员的期望相反。

于 2011-02-01T02:14:19.883 回答
0

字体是一个设计得很糟糕的对象,它违反了单一职责原则,你引用的困难源于此。Font 的问题在于它包含两件事:(1) 对如何绘制字体的描述,以及 (2) 具有这些属性的字体的 GDI 字体对象。前一种类型可以是可变的而没有后果,而使后一种类型可变会带来各种问题。

除其他事项外,请考虑应该如何跟踪典型控件(例如按钮)字体属性的所有权的问题?如果有时会更改与控件关联的字体,是否应该为每个控件创建一个单独的 Font 对象,并在将控件的字体更改为其他内容时处理它,或者应该保留一个正在使用的所有不同字体的列表为了避免创建过多相同的 Font 对象,还是什么?

If there existed a FontDescription struct (which was mutable, and not IDisposable) and things like Control.Font were of type FontDescription (or better yet, Control exposed a SetFont method with parameter of type FontDescription), the above question could be answered pretty simply. As it is, the most efficient approach for setting the Font of a control is to create a new font object (if one doesn't already have a suitable one), immediately Dispose it, and then do the assignment. The "font description" part of the Font remains quasi-valid even after Disposal, and that's all that's really needed for the Control.Font property.

于 2011-10-20T21:42:08.387 回答