【问题标题】:Dispose Recursive Class in C#在 C# 中处理递归类
【发布时间】:2018-02-11 22:47:05
【问题描述】:

更新:

对不起,我很困惑。混淆可能来自对 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中所写的内容相反,其中指出:

托管内存(使用 C# 运算符 new 分配的内存)不 需要明确释放。它会自动释放 垃圾收集器 (GC)。

也许这只是文档中的一个错误,让我失望了(该死的微软)。但也许——可能是在 GC 的早期,它并没有那么受信任,并且指导方针是“如果你知道自己在做什么,你可以清理自己”。现在它是如此值得信赖,以至于指导方针是“关于永远不要使用的托管资源,我们比你更了解”。如果没记错的话—— 那么这里显然有一些变化或转变。

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


老问题:

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

例如

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

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

在某些时候,来自 TreeView 的所有数据都被传输/保存到其他对象,我不再需要 TreeView。我猜我需要处理掉它? (当包含 ViewModel 的窗口关闭时,ViewModel 类对象保存在静态变量中)。

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

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

再说一遍 -

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

【问题讨论】:

  • 如果您的解决方案包括强制垃圾回收的要求,那么您做的事情非常非常错误。此外,您似乎对一次性用品和垃圾收集之间的关系有一些错误的看法;请记住,处置是释放不是垃圾收集的资源。您的任何选择都不是正确的做法。
  • 您真正想要解决的问题是什么?
  • 那么您需要进行一些以用户为中心的测量。您的用户有什么问题?一旦您可以衡量该问题,您就可以进行实验并发现您的更改是在经验上改善还是降低了用户体验。我注意到导致垃圾收集通常会降低用户体验,因为它们会使应用程序无响应。如果您没有影响用户的问题,那么请将您的宝贵时间花在“解决”没有人解决的问题之外的事情上。
  • 将模型存储在静态变量中似乎是一个坏主意,它会导致您试图解决的问题。你能避免将它存储在静态变量中吗?例如。将其存储在您的 ViewForm 中,因此当表单关闭时,模型将被 GC 收集。
  • 另请参阅我的回答下 Brian 的评论。

标签: c# mvvm dispose


【解决方案1】:

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

执行与释放、释放、 或重置非托管资源。

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

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

【讨论】:

  • @DavidRefaeli 如果是静态变量,您可以将其设置为 null 或依赖 GC 在您的应用终止后立即释放它。
  • 一旦不再存在对它们的引用,就依靠 GC 释放所有实例。那是没有变量指向它的时候 吹毛求疵,我知道,但与手头的问题有些相关。该规则是没有 reachable 引用的;如果无法访问具有指向它的引用的对象,则可以收集它们。这使 GC 能够收集相互引用但不可访问的对象。
  • 有点吹毛求疵,但 FileStream 是一个托管资源。应用程序程序员几乎不必处理非托管资源。
  • @HenkHolterman:FileStream 实现了IDisposable。因此,任何使用FileStream 作为实例属性的类(而不是本地包装在using 块中)仍应实现IDisposable(但不需要实现终结器)。
  • 是的,是的,是的。不太清楚你为什么认为你需要告诉我。
猜你喜欢
  • 2018-06-06
  • 2012-11-16
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 2014-05-23
  • 2020-03-30
相关资源
最近更新 更多