在list.removeAll中调用dispose

3

我对C#编程比较新,GC的概念以及它与IDisposable的关系还有点模糊。在垃圾回收方面,调用Dispose是什么意思?

具体来说,我想知道以下代码是否会偶尔失败,取决于垃圾回收启动的时间。(在我的测试中,我无法使其崩溃。)

//List<TestClass2> tc2List;
//TestClass2 invokes a thread. It implements IDisposable. 
//Its Dispose() sets a stop-condition for the thread,
//and joins the thread, awaiting it to stop. (may take 100 msek)

tc2List.RemoveAll(t =>
{
  if (String.Compare(t.Name, "Orange") == 0)
  {
    t.Dispose(); //May take up to 100 msek
    return true;
  }
  return false;
});

2
如果你是编程新手,可以忽略垃圾回收器。它会自动执行正确的操作。对于包含非托管资源(如连接)的对象,请使用“using”,否则不要显式调用dispose。 - Tim Schmelter
只有在涉及到非托管资源(例如操作系统文件句柄)时,IDisposable 才是相关的。通常与 IDisposable 相关的对象会与 GC 交互,以便在其内存被回收后自动进行处理作为一种安全措施,但这就是它们之间的联系了。GC 和 IDisposable 在其他方面没有关联。 - Jon
我在帖子中没有提到这一点,但是该类将保持串行端口直到线程停止。我需要确保它被释放。 - Jan Petter Jetmundsen
2
@Jon:“仅在涉及未托管的资源(即非内存资源;例如操作系统文件句柄)时,IDisposable 才相关。” - 这并不完全正确。例如,当关闭窗体时取消连接事件处理程序时,它也很重要。如果不取消连接事件处理程序,则可能出现内存泄漏。在这些情况下合理的解决方案是使用 IDisposable,即使您释放的“资源”不是未托管的。请参见例如 https://dev59.com/knRB5IYBdhLWcg3w9b59 (但也请参阅 http://msdn.microsoft.com/en-us/library/aa970850.aspx) - Matthew Watson
@MatthewWatson:当然,但那不是打算放进技术手册的;那只是一个专门针对完全新手的简短介绍。我相信你已经大致明白了。 - Jon
4个回答

4

你的代码能够正常运行,但是风格不佳。谓词(Predicates)不应该具有副作用。因此,你应该先处理元素,然后再移除它们。

Predicate<T> filter = t => t.Name == "Orange";
foreach(var t in tc2List.Where(filter))
  t.Dispose();
tc2List.RemoveAll(filter);

谢谢。我会记住这个的。谓词是另一个对我来说比较新的C#概念 :) - Jan Petter Jetmundsen
1
t.Dispose()之后,t.Name不会变成未定义吗? - mhu
@mhu 取决于你 dispose 对象时做了什么,但你是对的,之后继续使用它可能不是一个好主意。 - CodesInChaos

2
我想知道以下代码是否会偶尔失败,这取决于垃圾回收何时启动。
不会失败。
//Its Dispose() sets a stop-condition for the thread,
//and joins the thread, awaiting it to stop. (may take 100 msek)

这是一个略微不典型的Dispose()使用方法,但并没有错误。更有效的方法是使用不同的Stop()以便你可以一次性停止所有线程。或者从Parallel.ForEach()中调用Dispose()。但无论你选择哪种方法,它都不会受到GC的阻碍,也不会阻碍GC。


1

你的TestClass2中有finalize方法吗?

释放主要属性

  1. 这必须在实现IDispose接口的类中实现。
  2. 它是释放非托管资源(如文件、句柄和连接等)的正确位置。
  3. Dispose()方法在代码本身中被显式调用。
  4. 对于实现IDispose的对象,在“using”中使用时,Dispose()方法会自动调用。

请参考链接


没有finalize方法在我的TestClass中。根据Henk Holterman的评论,我意识到我也不需要Dispose。我实现了一个Stop()方法来停止我正在使用的线程。 - Jan Petter Jetmundsen
没错,也许你想看一下我的回答中的链接,那里可以看到如何以及为什么应该使用dispose。 - D J

0
在垃圾回收方面,调用Dispose是什么意思?
调用Dispose意味着您正在使用Dispose方法的自己的实现强制清理东西(字面上的内存)。注意:(某些框架类会为您调用Dispose的实现。例如System.Windows.Forms.Form)
相比之下,垃圾回收是.NET运行时的一个功能,它将自动为您清理东西。我所说的“自动”是指由运行时处理的内存压力和其他因素。
我建议一个简单的策略。如果您认为内存需要保留的时间超过了所需时间并且会影响应用程序,请使用Dispose()。否则就让运行时处理,它会在对象超出范围时自动清理(即完成)。GC有自己的算法来进行清理,但是您可以更大程度地依赖它。
下一个问题是,具体来说,我想知道以下代码是否可能偶尔失败,这取决于垃圾回收何时启动
我想没有。由于GC的启动,代码的失败取决于您如何编写TestClass2的终结器。毫无疑问,您的调用t.Dispose()不会与GC冲突。

清理事物(字面上的内存)- 不,Dispose根本不会清理/释放/收集内存。 - H H
Dispose的语义意思就是应该这样做,如果我理解正确的话。 - Soundararajan
1
Dispose 的设计目的是仅清理非托管资源(例如关闭处理程序、清理非托管内存等),不会清理托管内存。因此,说 Dispose 清理内存是非常错误的。 - Archeg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接