我有一个FileUploader类,可以选择为其提供一个zip文件,然后将其提取到临时位置并返回文件路径。
根据我的理解,在FileUploader类上实现IDisposable
接口并使用Dispose
方法删除所有临时文件将使该类在其引用脱离上下文后立即自行清理?
但事实似乎并非如此 - 任何人都可以解释我如何去实现我想要实现的目标吗?
更新
为了澄清,我的代码是:
public ActionResult ImportFile()
{
FileUploader uploader = new FileUploader(ControllerContext, "file"); // where "file" is the posted form's file element
uploader.SaveOrExtractFilesToTempLocation();
foreach (string file in uploader.files)
{
try
{
// do some stuff
}
catch (Exception err)
{
// let the user know
}
}
return View();
}
我试图在ImportFile()方法完成后让FileUploader删除所有临时文件
答案 0 :(得分:7)
“脱离背景”尚不清楚;你必须这样做:
using(var file = new FileUploader(...)) {
// do the work here
}
没有using
,没有特殊处理。然后编译器将其转换为:
var file = new FileUploader(...);
IDisposable tmp = file;
try {
// do the work here
} finally {
if(tmp != null) tmp.Dispose();
}
并且此会导致确定性清理。
答案 1 :(得分:7)
您需要正确实现IDisposable。喜欢下面的课程。
using System.IO;
/// <summary>
/// Represents a temporary storage on file system.
/// </summary>
public sealed partial class TempStorage
: IDisposable
{
#region Constructor
private TempStorage()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TempStorage"/> class.
/// </summary>
/// <param name="path">The path to use as temp storage.</param>
public TempStorage(string path)
{
this.Path = path;
this.Clear();
this.Create();
}
#endregion
#region Properties
private string Path
{
get;
set;
}
#endregion
#region Methods
private void Create()
{
try
{
if (!Directory.Exists(this.Path))
{
Directory.CreateDirectory(this.Path);
}
}
catch (IOException)
{
}
}
public void Clear()
{
try
{
if (Directory.Exists(this.Path))
{
Directory.Delete(this.Path, true);
}
}
catch (IOException)
{
}
}
#endregion
#region IDisposable
/// <summary>
/// An indicator whether this object is beeing actively disposed or not.
/// </summary>
private bool disposed;
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Throws an exception if something is tried to be done with an already disposed object.
/// </summary>
/// <remarks>
/// All public methods of the class must first call this.
/// </remarks>
public void ThrowIfDisposed()
{
if (this.disposed)
{
throw new ObjectDisposedException(this.GetType().Name);
}
}
/// <summary>
/// Releases managed resources upon dispose.
/// </summary>
/// <remarks>
/// All managed resources must be released in this
/// method, so after disposing this object no other
/// object is beeing referenced by it anymore.
/// </remarks>
private void ReleaseManagedResources()
{
this.Clear();
}
/// <summary>
/// Releases unmanaged resources upon dispose.
/// </summary>
/// <remarks>
/// All unmanaged resources must be released in this
/// method, so after disposing this object no other
/// object is beeing referenced by it anymore.
/// </remarks>
private void ReleaseUnmanagedResources()
{
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
/* Release unmanaged ressources */
this.ReleaseUnmanagedResources();
if (disposing)
{
/* Release managed ressources */
this.ReleaseManagedResources();
}
/* Set indicator that this object is disposed */
this.disposed = true;
}
}
#endregion
}
然后在main方法中使用using-block中的类,如下所示:
using(TempStorage myStorage = new TempStorage("C:\temp")
{
// rest of the main method here...
}
答案 2 :(得分:2)
Dispose
关键字包装上下文时, using
才会自动生成:
using (FileUploader uploader = new FileUploader(...))
uploader.UploadFiles();
答案 3 :(得分:1)
你可以实现终结器,这样如果你忘记拨打Dispose
(你真的不应该!)并在你的终结器中调用Dispose
。当对象被垃圾收集时会调用它 - 但它是不确定的,即没有办法找出它何时被调用。
但无法保证。
答案 4 :(得分:0)
正如其他人已经说过的那样,除非上下文包含Dispose
关键字,否则不会自动调用using
。但是,您可以实现Dispose和Finalize模式(从终结器/析构函数调用Dispose
方法)。这样,即使您的代码没有直接调用Dispose
,您也可以使用故障保护并删除临时文件(因为垃圾收集器最终会调用终结器)。
This article说明了这一概念,并提供了有关最终确定如何运作的一些见解。
答案 5 :(得分:0)
与其他人一样,最好的办法是将其包装在using语句中以强制调用Dispose方法。我相信这就是微软推荐使用任何实现IDispose的方法,至少基于他们的代码分析规则。
答案 6 :(得分:0)
IDisposable适用于对象以某种方式在对象消失之前清除的方式更改外部的内容。临时文件的创建似乎符合条件。但是,有一些警告:
我并不特别喜欢终结者;重点应放在使处理器工作。