Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么字体是不可变的?_C#_Fonts_Immutability - Fatal编程技术网

C# 为什么字体是不可变的?

C# 为什么字体是不可变的?,c#,fonts,immutability,C#,Fonts,Immutability,字体不可变会使程序员和GC都感到苦恼,因为每次都需要创建一个新实例 那么为什么字体是不可变的引用类型呢?它简化了渲染系统的使用 如果框架允许字体是可变的,它将需要检测更改,并定期修改呈现方式。因为字体创建了一个本机资源,所以保持此不变可以防止系统担心必须在内部重复创建句柄 此外,我不同意“程序员的痛苦”。通过使字体不可变,它使用户创建字体对象时发生的事情更加明显。如果您想要一种新字体,您需要创建一个新的字体对象,这反过来又会创建新的本机字体资源。使字体不可变可以更清楚地了解发生了什么-您不太可能

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


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

它简化了渲染系统的使用

如果框架允许字体是可变的,它将需要检测更改,并定期修改呈现方式。因为字体创建了一个本机资源,所以保持此不变可以防止系统担心必须在内部重复创建句柄

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


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

它们不是结构,因为它们需要有终结器来包装底层对象并提供合理的
IDisposable
实现。如果
Dispose()
您自己的
结构副本会发生什么情况?你每次都克隆句柄吗

其实GC上没有太大的压力


它还允许安全地重复使用
字体
,而无需担心在操作中途会发生更改-p我不同意,这让程序员很苦恼。BCL中有很多不可变的类型,程序员每天都在使用这些类型,不会引起任何问题。例如,System.String

不可变的好处之一是不必每次都创建新实例。您可以随时重复使用相同的字体类型,因为它不会改变。另一方面,如果它是可变的,你需要每次都复制一份,以保证没有其他人从你下面把它改出来


最后,字体实际上并不是严格意义上的一个不变的类。它实现IDisposable,并在Dispose方法中分解底层本机对象

好吧,问问自己一些问题

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

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

第二,字体在逻辑上更像是一个可以复制的值,还是更像是一个可以引用的单一对象?我不想有“两本”的《赫尔维蒂卡》;我想提到赫尔维蒂卡。我认为数字有不同的副本,用于不同的目的——当我的购物清单上有12件物品,钥匙圈上有12把钥匙时,我不认为这两件事都是“指12”


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

你可以说这让开发人员很苦恼。但你也可以在相反的情况下提出同样的论点

例如:

// 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
是可变的,则上述代码会将按钮和文本框的字体同时设置为粗体,这与开发人员的期望相反。

font是一个设计拙劣的对象,违反了单一责任原则,您列举的困难正是源于此。字体的问题在于它包含两个方面:(1)字体应该如何绘制的描述,以及(2)具有这些属性的字体的GDI字体对象。前一种类型可以是可变的,没有后果,而使后一种类型可变会带来各种各样的问题

除此之外,考虑如何跟踪典型控件(例如按钮)字体属性的所有权的问题。如果有时要更改与控件关联的字体,是否应该为每个控件创建一个单独的字体对象,并在将控件的字体更改为其他字体时将其丢弃,还是应该保留一个正在使用的所有不同字体的列表,以避免创建过多的相同字体对象,或者是什么


如果存在FontDescription结构(它是可变的,不可IDisposable)和Control.Font之类的类型是FontDescription(或者更好的是,Control公开了一个参数为FontDescription类型的SetFont方法),上述问题可以很简单地回答。实际上,设置控件字体的最有效方法是创建一个新的字体对象(如果还没有合适的字体对象),立即处理它,然后进行赋值。字体的“字体描述”部分即使在处理后仍保持准有效,这就是Control.font属性真正需要的。

更不用说,使用托管字体对象的任何对象(例如窗口)都必须检测本机句柄何时更改,并将新句柄与其自己的本机对象关联(例如HWND)。我一直认为复制和轻微更改现有字体对象是不必要的痛苦。我从来没有考虑过他们创建本机资源,所以对于有见地的答案+1。尽管他们没有做出任何AsBold()命令,但太糟糕了方法,该方法只返回粗体的新实例。@Itay:您注意到了吗?我同意类似于
Label1.Font=new Font(Label1.F