我如何知道类是否是非托管资源的包装器

时间:2016-03-09 20:58:40

标签: c#

我如何知道C#中的类是否是非托管的,因此如果我在自定义类中使用它,我知道是否必须实现IDisposable接口?

如果我在MSDN网络上得到这个article,我总是必须在使用非托管资源时实现IDisposible接口。

所以我创建了一个你可以在下面找到的小例子:

class TestClass
{
    private StreamReader reader;

    public UsingTestClass()
    {
        reader = File.OpenText("C:\\temp\\test.txt");

        string s;
        while (!string.IsNullOrEmpty(s = reader.ReadLine()))
        {
            Console.WriteLine(s);
        }

    }
}

以下MSDN article例如说File是一个无法管理的资源,它也在我的测试类中使用。那么我怎么看,这个课程是无人的? 编译器和ReSharper没有抱怨任何事情。

提前致谢。

1 个答案:

答案 0 :(得分:6)

  

如何知道C#中的类是否不受管理

这会立即让你离开错误的轨道,管理C#中的所有类。该语言根本不支持使用非托管类。没有一种.NET语言可以做,除了一种:C ++ / CLI。这是一种非常典型的语言,专门用于帮助程序员使用本机C ++类。该语言的使用是专门的,与此问题无关。

重要的是托管类是否是非托管资源的包装器。包装器是一种具有纯托管接口的类,但内部使用非托管资源,通常通过带有[DllImport]属性的pinvoke。资源几乎总是用IntPtr表示。非托管句柄或指针。

这样的包装器需要一个终结器来确保始终释放非托管资源。如果没有发生这种情况,那么你就会遇到 leak ,当操作系统对使用太多资源的程序感到不满时,这种错误会最终导致程序崩溃。

由于它有终结器,它还实现了IDisposable。允许程序在GC调用终结器之前提前释放非托管资源。使用Dispose()方法或 using 语句是可选的,终结器足以确保完成作业。

但有时候终结器不够好,因为程序不能足够快地生成垃圾,然后你帮忙就非常重要了。您无法真正知道是否必须提供帮助,因此大多数.NET程序员都会这样做。一个子集从来没有,也没有注意到多年的编程问题。我们最终会在SO上听到他们的声音:)

您的StreamReader示例是进入下一步的好例子。 StreamReader实际上并不包装非托管资源。它的所有代码都是用C#编写的,它没有任何pinvoke,它的体内没有非托管的骨骼。因此有终结者。但仍然有一个Dispose()方法。

StreamReader被“感染”了。它也是一个包装类,但对于Stream而不是IntPtr。纯粹管理的抽象.NET类型,本身就是一个包装器。它实现了IDisposable,现在StreamReader 已经来实现它。因此,当您调用StreamReader的Dispose()方法时,可以运行Stream.Dispose()方法。

这是分层在工作中,有一个类的层次结构。 StreamReader包装了包装FileStream的Stream,它包装了SafeFileHandle,其中实际上包装了IntPtr。只有SafeFileHandle有一个终结器。

理解分层是每个人都放弃的地方,这需要深入了解这些.NET类的结构。你可以到达那里但需要数年时间。有三个基本快捷方式:

  • 了解操作系统的工作原理。为您提供文件是操作系统资源的洞察力,请注意您在使用文件时需要处理或关闭文件。

  • 对您使用的类使用MSDN库文章。当你看到它有一个Dispose()方法时,几乎总是有充分的理由使用它。有时没有,但无论如何你都不会错。

  • 遇到麻烦,犯下每个程序员需要犯的所有错误,使用SO或内存分析器来找出你做错了什么。学习如何正确地做到这一点没有错。