在 C# 中处理递归 Class

Dispose Recursive Class in C#

更新:

对不起,我很困惑。混淆可能来自对 GC/Dispose 的旧看法与新看法。

如果你看这里官方Microsoft Documentations,说明Dispose模式也用于释放托管资源:

protected override void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            // Release **managed** resources. (!!!!!)
        }
        // Release unmanaged resources.
        // Set large fields to null.
       // Call Dispose on your base class.
        disposed = true;
    }
    base.Dispose(disposing);
}

这与 new version 中的内容相反,其中指出:

Managed memory (memory allocated using the C# operator new) does not need to be explicitly released. It is released automatically by the garbage collector (GC).

也许这只是文档中的一个错误,让我失望了(该死的微软)。但也许 - 可能是在 GC 的早期,它并不那么受信任,指南是 "you can clean yourself, if you know what you're doing"。现在它是如此值得信赖,指南是 "on managed resources don't ever use, we know better than you"。如果这不是一个错误—— 那么这里显然有一些改变或转变。

至于问题 - 我不会做任何事情,让 GC 做它最擅长的事情。


老问题:

我有一个 TreeView ViewModel class,其中有节点,它们是递归的 classes(它们可以包含自己)。

例如

class RootViewModel // root
{
   List<ItemViewModel> Children = new List<ItemViewModel>();
}

class ItemViewModel // node
{
    List<ItemViewModel> Children = new List<ItemViewModel>();
}

在某些时候,TreeView 中的所有数据都transferred/saved 到其他对象,我不再需要 TreeView。我猜我需要处理掉它? (当包含 ViewModel 的 window 关闭时,ViewModel class 对象保存在一个静态变量中)。

我需要单独处理每个节点(递归处理)还是将根对象设置为 null 并调用 GC 就足够了?

我应该注意,我的处置没有任何非托管资源,我只是将每个节点的子列表中的所有子节点设置为 null。

再说一遍 -

  1. 选项A:将静态对象设置为空,调用GC.Collect()。
  2. 方案B:递归设置所有节点为空,设置静态对象为空, 调用 GC.Collect(). - 根据目前的答案和评论似乎是不可能的
  3. 选项 C:GC 发现您停止使用静态对象,因此它会自行处理它。

您应该Dispose仅释放非托管资源,例如一些文件流。因此,当您没有任何非托管资源时,根本不需要使用 Dispose。见 the docs:

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

相反,只要不再有对它们的引用,就依靠 GC 释放所有实例。那就是没有变量指向它的时候。所以在父节点被 GC 释放的那一刻,它的子节点也是(假设你没有任何其他变量指向它们)。然而调用 GC.Collect 几乎 总是 一个坏主意,GC 通常做得很好,你不应该调查。

然而,将您的变量设置为 null 不会将它们标记为垃圾收集,除非您有一些非常大的代码块(例如,一个包含数千行的方法)。在这种情况下,您的变量可能很长时间都不会超出范围。因此,这样做更像是代码异味的标志,您应该将代码分成更小的部分,只做一件事情。