我应该在System.Drawing.FontFamily.Families
属性中处理每种字体,这会返回一个实现FontFamily
的{{1}}类数组吗?
在属性访问者返回的极少数情况下,我是否应该处置任何其他类实例或实现IDisposable
的实例数组?
答案 0 :(得分:2)
我使用Reflector查看了代码,我可以告诉您,当您访问该属性时,正在使用SafeNativeMethods.Gdip.GdipCloneFontFamily()
为每种字体分配一大堆Font句柄。
如果不是太难,你应该这样做。如果不这样,终结器将释放为每种字体分配的操作系统句柄,但如果有很多字体,你真的不想花很长时间来处理它们。在调用终结器之前可能需要任意长的时间。
如果您反复访问Families[]
属性,最终可能会出现大量未发布的操作系统句柄,这可能会导致问题。
这是FontFamily
类型的Dispose()方法:
private void Dispose(bool disposing)
{
if (this.nativeFamily != IntPtr.Zero)
{
try
{
SafeNativeMethods.Gdip.GdipDeleteFontFamily(new HandleRef(this, this.nativeFamily));
}
catch (Exception exception)
{
if (ClientUtils.IsCriticalException(exception))
{
throw;
}
}
finally
{
this.nativeFamily = IntPtr.Zero;
}
}
}
请注意,您将错过对GdipDeleteFontFamily()
的调用,这将释放该字体的操作系统句柄。
(旁注:微软关于此类事情的文档很差,因为他们的示例代码通常忽略了处理字体的问题。)
以下是Families
的实施:
public FontFamily[] Families
{
get
{
int numFound = 0x0;
int status = SafeNativeMethods.Gdip.GdipGetFontCollectionFamilyCount(new HandleRef(this, this.nativeFontCollection), out numFound);
if (status != 0x0)
{
throw SafeNativeMethods.Gdip.StatusException(status);
}
IntPtr[] gpfamilies = new IntPtr[numFound];
int num3 = 0x0;
status = SafeNativeMethods.Gdip.GdipGetFontCollectionFamilyList(new HandleRef(this, this.nativeFontCollection), numFound, gpfamilies, out num3);
if (status != 0x0)
{
throw SafeNativeMethods.Gdip.StatusException(status);
}
FontFamily[] familyArray = new FontFamily[num3];
for (int i = 0x0; i < num3; i++)
{
IntPtr ptr;
SafeNativeMethods.Gdip.GdipCloneFontFamily(new HandleRef(null, gpfamilies[i]), out ptr);
familyArray[i] = new FontFamily(ptr);
}
return familyArray;
}
}
请注意它是如何计算有多少字体的,然后为每个字体调用GdipCloneFontFamily()
并使用返回的FontFamily
初始化新的IntPtr
。