我应该处理FontFamily.Families结果吗?

时间:2014-03-03 12:56:58

标签: c# .net fonts dispose idisposable

我应该在System.Drawing.FontFamily.Families属性中处理每种字体,这会返回一个实现FontFamily的{​​{1}}类数组吗?

在属性访问者返回的极少数情况下,我是否应该处置任何其他类实例或实现IDisposable的实例数组?

1 个答案:

答案 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