我们如何区分 C# 中的托管资源和非托管资源? TextFieldParser 是非托管的吗?

How do we distinguish between managed and unmanaged resources in C#? Is TextFieldParser unmanaged?

如何使用Microsoft.VisualBasic.FileIO.TextFieldParser解析文本输入。在给我的示例中,使用关键字 using

调用 TextFieldParser
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(new StringReader(str)))

虽然在 some further researches 之后,我注意到 TextFieldParser 使用 using 关键字的做法并不普遍。

据我了解,.Net 框架同时具有托管和非托管资源。当我们使用非托管资源时,我们应该 worry about 内存泄漏,因此我们应该注意我们使用的非托管资源的处置。一种最好的方法是将它们放在 using 上下文中。

这一切让我有两个问题,一个是特殊的,一个是一般的。这是我的问题:

  1. 具体:TextFieldParser 是托管的还是非托管的?
  2. 一般:有没有一种确定的方法让我们知道资源是托管的还是非托管的(比如查看[=45中的X东西=],或类似的东西,甚至检查 MSDN 中的内容 - 如果需要检查 - 都可以)。根据我的简短编程经验,有人告诉我一些指导,例如 (i) 大多数 .Net classes 是托管的,(ii) System.Drawing classes 有一些非托管的资源,(iii) 提防所有数据库、网络和 COM classes,因为它们通常是非托管的,等等……我一直在不断添加列表,直到现在。但我想知道是否有任何 确定 方法可以知道这一点?

如果更有经验的人可以帮助进一步指导我解决这个问题,我将不胜感激。

任何 类 实现 IDisposable 接口的使用都应该包装在 using (...) {} 中,或者在适当的地方妥善处理。

你没抓住重点。每当 class 实现 IDisposable 时,您应该在完成后调用 Dispose

是否 class 使用非托管资源是 class 内部的,你根本不应该关心它。每个使用非托管资源的 class 还应该有一个终结器,如果您没有明确处理 class,它会清除那些非托管资源。 Dispose 只允许您以更加确定和直接的方式清理其资源(托管和非托管,尽管这不一定意味着立即释放内存)。例如,Disposeing a FileStream 将立即释放文件句柄,而如果您不 Dispose(或 Close),文件将被打开直到下一个收集和定稿。

编辑:

为了表明 Dispose 也可能是清理托管资源所必需的,我们只需要查看事件处理程序。特别是,当您订阅生命周期比您长的 class 事件时:

var control = new MyHelperControl();
MyParentForm.Click += control.DoSomething();

现在,即使 control 超出范围,只要 MyParentForm 它就会存在 - 它仍然被事件处理程序引用。当父应用程序与整个应用程序具有相同的生命周期时,同样的问题会发展到荒谬的程度——这可能是一个巨大的内存泄漏。例如,在应用程序的主窗体或静态事件上注册事件处理程序。

Dispose 中可能还会发生其他事情。例如,再次使用 Windows 表单,当您在 Control 上调用 Dispose 时,会发生很多事情:

  • 释放所有非托管资源。由于 Winforms 控件在某种程度上是本机控件的包装器,因此这通常是很多资源 - 控件本身、任何笔、画笔、图像……所有这些都是本机资源。如果您忘记 Dispose,它们也会被释放,因为它们都有终结器,但这可能需要更多时间——当您创建和销毁大量这些对象时,这尤其痛苦。例如,GDI+ 对象句柄的供应有限,如果您 运行 出局,您将获得 OutOfMemoryException 并且您出局。
  • 处理所有sub-controls。
  • 删除所有上下文菜单处理程序(请记住,上下文菜单是一个单独的组件,仅链接到另一个控件)。
  • 删除所有数据绑定。
  • 从父容器中删除自身
  • 如果控件是 window 具有自己的消息循环,则终止消息循环。

有趣的是,非托管资源最不重要,真的 - 它们总是有终结器。托管资源更棘手,因为您或多或少地被禁止在终结器中处理托管引用(因为它们可能已经被释放,或者它们可能正在被释放,或者它们可能在中间开始被释放你的终结器......这很复杂)。所以在你的终结器中做 MyParentForm.Click -= this.OnClick; 并不是一件好事 - 更不用说它需要你使每个这样的 class 可终结,这并不是完全免费的,特别是当你期望终结器时实际上 运行(当您执行 Dispose 时,GC 会收到此实例不再需要终结的警报)。