我问question这个方法:
// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
TextWriter textWriter = new StreamWriter(filename);
xmlSerializer.Serialize(textWriter, toSerialize);
textWriter.Close();
}
在回复中,我将此作为补充说明:
确保始终处理一次性资源,例如流和文本阅读器和编写器。在SerializeObject方法中似乎不是这种情况。
所以,我可以说,对于那些编写C#一年或两年的人来说,这似乎是非常蹩脚的,但为什么我必须处理它呢?
是否testWriter
有一个dispose方法,但是垃圾收集不应该处理吗?我从Delphi来到C#。在Delphi中我不得不清理所有东西,所以这不是我想要变懒的情况。我刚刚被告知,如果你强行释放你的对象占用的内存,那么它可能会导致坏事。有人告诉我“让垃圾收集者去做吧。”
textWriter
击中了磁盘。)答案 0 :(得分:15)
这里的经验法则非常简单:始终在实现Dispose()
的对象上调用IDisposable
(并非所有对象都可以)。你不会总是知道对象必须实现Dispose的原因,但是你应该认为它是有原因的。
确保执行此操作的最简单方法是using
:
using (TextWriter tw = new StreamWriter(fileName))
{
// your code here
}
这将在using块的末尾自动调用Dispose()
(它与使用try / catch / finally和finally块中的Dispose()基本相同。)
有关Dispose如何使用垃圾收集的更多信息,请see here。
答案 1 :(得分:12)
你是正确的,对于正确编写的代码,GC最终将清理本机资源。该对象将有一个终结器,在最终确定期间将释放必要的本机资源。
然而,当发生这种情况时,非常不确定。此外,它有点倒退,因为您正在使用旨在处理托管内存的GC作为管理本机资源的方法。这导致了有趣的案例,并且可能导致本机资源比预期更长时间保持活跃,从而导致
using / dispose模式为清除本机资源添加了确定性并消除了这些问题。
答案 2 :(得分:4)
如果你知道你不会使用某种资源,你可以自己处理它;你肯定会比垃圾收集器更快,并允许其他人使用该文件或你打开的更快。最简单的方法是使用TextWriter或using
中的任何其他资源:
using (TextWriter textWriter = new StreamWriter(filename))
{
xmlSerializer.Serialize(textWriter, toSerialize);
}
这基本上确保了TextWriter被放置在最后。无论如何,你不需要它。
答案 3 :(得分:4)
垃圾收集器会释放所有资源,但是这样做的时间是未定义的。 Dispose方法提供了一种立即释放非托管资源的方法。
答案 4 :(得分:3)
实际上你已经在处理它了,因为textWriter.Close方法就是这样做了。
public virtual void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
因此您可以将代码更改为。这个
public static void SerializeObject<T>(this T toSerialize, String filename)
{
TextWriter textWriter;
try
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
textWriter = new StreamWriter(filename);
xmlSerializer.Serialize(textWriter, toSerialize);
}
finally
{
textWriter.Close();
}
这与using()在其他答案中的作用非常相似。
不这样做的影响是,如果Serialize发生错误,那么在框架放弃文件锁定之前(当它处理fReachable队列时)会有一段时间。
我知道FxCop告诉你何时实施IDisposable但是我认为除了查看Docs以及查看对象是否包含IDisposable(或intellisense)之外,还有任何简单的方法可以找出你需要调用Dispose的时间。 / p>
答案 5 :(得分:2)
如果您正在使用本机资源(例如文件句柄),那么您应该尽快调用Dispose()来关闭它们,而不是在GC运行时(可能在更高的gc代中更晚)。并且您希望关闭该文件,因为文件访问通常以某种方式锁定文件。
答案 6 :(得分:1)
如果要打开资源(例如文件或打开数据库连接),则释放资源将释放其对资源的保留。如果您不这样做,那么其他人可能无法连接到数据库或使用该文件。
作为一般的经验法则....如果类实现了IDisposable接口,那么在完成它时应该调用Dispose()方法。他们很可能有理由让它成为一次性的:)
答案 7 :(得分:1)
来自TextWriter.Dispose文档:
注意始终在您之前调用Dispose 发布你的最后一个引用 的TextWriter。否则,资源 它的使用不会被释放,直到 垃圾收集器调用 TextWriter对象的Finalize方法。
来自Object.Finalize文档:
终结者的确切时间 在垃圾收集期间执行 未定义。资源不是 保证在任何时候发布 具体时间,除非调用关闭 方法或Dispose方法。
和
Finalize方法可能无法运行 完成或可能根本不运行 以下特殊情况 情况:
另一个终结器无限期阻塞 (进入一个无限循环,试图 获得一个永远无法获得的锁 等等)。因为运行时尝试 运行终结器完成,其他 如果a,可能不会调用终结器 终结者无限期地阻止。
该过程终止而不给予 运行时有机会清理。在 这种情况下,运行时的第一个 流程终止通知是 DLL_PROCESS_DETACH通知。
运行时继续Finalize 关闭期间的对象只有在 可终结对象的数量 继续减少。
答案 8 :(得分:0)
垃圾收集器确实会“照顾好”。迟早。当它在下一次垃圾收集之后调用终结器时。
调用Dispose
可确保尽快释放资源(如文件句柄),从而使其可供系统中的其他进程重用。大多数情况下,您不会注意到自己调用Dispose
和让垃圾收集器处理它之间的区别。但有时你会。例如,创建大量HttpWebResponse
对象的Web爬网程序如果在使用后不进行处理,将很快耗尽连接。 (不是说我遇到了那个问题......不,不是我。)
答案 9 :(得分:0)
调用Dispose而不是等待GC的原因通常是因为您正在使用要尽快释放的有限系统资源,以便其他进程或线程可以使用它。对于具有IDisposable模式的对象,"using"构造是一种简单易读的方法,可确保调用Dispose。
答案 10 :(得分:0)
通常,当您不再需要它们时,您必须处置它们。
当你完成它们时不处理对象将意味着阻止对其他处理/应用程序的访问。
答案 11 :(得分:0)
一个程序员认为一个人不必担心处理事情,因为终结者会照顾他们就像一个司机认为一个人不必担心避免碰撞,因为汽车有一个安全气囊。是的,安全气囊会让事情更有生存能力,但是......