Dispose()或Finalize()是否应该用于删除临时文件?

我有一个类,它在活动时使用临时文件( Path.GetTempFileName() )。 我想确保在关闭程序后这些文件不会留在用户的硬盘上占用空间。 现在我的类有一个Close()方法,它检查该类使用的任何临时文件是否仍然存在并删除它们。

将此代码放在Dispose()或Finalize()方法中会更有意义吗?

更好的是用FileOptions.DeleteOnClose创建文件。 这将确保操作系统在您的进程退出时强制删除文件(即使在粗鲁中止的情况下)。 当然,你完成后仍然需要自己关闭/删除文件,但这提供了一个很好的支持,以确保你不允许文件永远存在

我会两个都做; 让这个级别一次性,并让终结器清理它。 安全有效地采用标准模式: 使用它而不是试图自己推断出正确的模式是什么。 这很容易出错。 仔细阅读:

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

请注意,在编写终结器时,您必须非常小心 。 当终结器运行时,您的许多正常假设都是错误的:

  • 竞争条件或死锁有各种各样的潜力,因为你不再在主线程上,你在终结者线程上。

  • 在常规代码中,如果您在对象内部运行代码,那么您就知道对象引用的所有内容都是活动的。 在终结器中,对象引用的所有内容可能刚刚完成! 死对象的终结器可以按任何顺序运行,包括在“父”对象之前完成的“子”对象。

  • 在常规代码中,将对象的引用分配给静态字段可能是完全合理的。 在终结器中,您分配的引用可能是已经死亡的对象 ,因此赋值会使死对象恢复生命。 (因为静态字段引用的对象总是活着的。)这是一种非常奇怪的状态,如果你这样做,就不会发生任何令人愉快的事情。

  • 等等。 小心。 如果你写一个非平凡的终结器,你应该完全理解垃圾收集器的操作。

文件是非托管资源,您实现IDisposable以清除您的类所依赖的非托管资源。

我已经实现了类似的类,尽管从未在生产代码中。

但是,我理解您对此的暂时性 – 用户与应用程序之外的文件进行交互可能会使事情变得棘手,并在处置过程中造成问题。 但是,对于应用程序创建/删除的任何文件,这都是相同的,无论它是否通过Dispose()方法进行整理。

我不得不说实施IDisposable是一个合理的选择。

David M. Kean在Path.GetTempFileName上的MSDN条目上建议了一个很好的方法。 他创建了一个实现IDisposable的包装类,它将自动删除该文件:

 public class TemporaryFile : IDisposable { private bool _isDisposed; public bool Keep { get; set; } public string Path { get; private set; } public TemporaryFile() : this(false) { } public TemporaryFile(bool shortLived) { this.Path = CreateTemporaryFile(shortLived); } ~TemporaryFile() { Dispose(false); } public void Dispose() { Dispose(false); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { _isDisposed = true; if (!this.Keep) { TryDelete(); } } } private void TryDelete() { try { File.Delete(this.Path); } catch (IOException) { } catch (UnauthorizedAccessException) { } } public static string CreateTemporaryFile(bool shortLived) { string temporaryFile = System.IO.Path.GetTempFileName(); if (shortLived) { // Set the temporary attribute, meaning the file will live // in memory and will not be written to disk // File.SetAttributes(temporaryFile, File.GetAttributes(temporaryFile) | FileAttributes.Temporary); } return temporaryFile; } } 

使用新类很简单,只需键入以下内容:

 using (TemporaryFile temporaryFile = new TemporaryFile()) { // Use temporary file } 

如果您在构建TemporaryFile之后决定要阻止它被删除,只需将TemporaryFile.Keep属性设置为true:

 using (TemporaryFile temporaryFile = new TemporaryFile()) { temporaryFile.Keep = true; } 

我总是让我的类指向临时文件IDisposable ,并且通常实现一个调用我的dispose方法的终结器。 这似乎是IDisposable MSDN页面建议的范例。

相关代码如下:

 public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user's code. Managed and unmanaged resources // can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be disposed. private void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) { // Dispose managed resources. } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. // Note disposing has been done. disposed = true; } } // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. // Do not provide destructors in types derived from this class. ~MyResource() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false); } 

如果您希望重新使用临时文件,例如open \ close \ read \ write \ etc,那么在AppDomain卸载级别清除它们会很有用。

这可以与将temp文件放在临时位置的一个众所周知的子目录中并确保在应用程序启动时删除该目录以确保处理不干净的关闭一起使用。

该技术的一个基本示例(为了简洁,删除了删除exception处理)。 我在基于文件的unit testing中使用这种技术,它有意义且有用。

 public static class TempFileManager { private static readonly List TempFiles = new List(); private static readonly object SyncObj = new object(); static TempFileManager() { AppDomain.CurrentDomain.DomainUnload += CurrentDomainDomainUnload; } private static void CurrentDomainDomainUnload(object sender, EventArgs e) { TempFiles.FindAll(file => File.Exists(file.FullName)).ForEach(file => file.Delete()); } public static FileInfo CreateTempFile(bool autoDelete) { FileInfo tempFile = new FileInfo(Path.GetTempFileName()); if (autoDelete) { lock (SyncObj) { TempFiles.Add(tempFile); } } return tempFile; } } 

绝对。 这样,您可以确保在存在exception的情况下进行清理。

您绝对应该使用Dispose来清理资源,但请确保实现IDisposable接口。 您不想只添加名为Dispose的方法。