代码之家  ›  专栏  ›  技术社区  ›  Jimbo

使用IDisposable清理临时文件

  •  9
  • Jimbo  · 技术社区  · 15 年前

    根据我的理解,执行 IDisposable FileUploader类上的接口,并使用 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();
        }
    

    我试图让FileUploader在ImportFile()方法完成后删除所有临时文件

    7 回复  |  直到 15 年前
        1
  •  7
  •   Kevin Vaughan    15 年前

    您需要正确实现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
    }
    

    然后在主方法中使用using块中的类,如下所示:

    using(TempStorage myStorage = new TempStorage("C:\temp")
    {
        // rest of the main method here...
    }
    
        2
  •  8
  •   Marc Gravell    15 年前

    “断章取义”还不清楚;你必须:

    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();
    }
    

    是的 这会导致确定性的清理。

        3
  •  2
  •   Tim Robinson    15 年前

    Dispose 只有在使用 using

    using (FileUploader uploader = new FileUploader(...))
        uploader.UploadFiles();
    
        4
  •  1
  •   Aliostad    15 年前

    您可以实现终结器,以便在忘记调用 Dispose (你真的不应该这样!)打电话给 处置 在你的定稿器里。当对象被垃圾收集时,这将被调用,但它是不确定的,也就是说,无法确定何时调用它。

    不保证 .

        5
  •  0
  •   Anders Fjeldstad    15 年前

    Dispose 除非上下文用 using 处置 处置 直接(因为垃圾收集器最终会调用终结器)。

    This article

        6
  •  0
  •   Jason    15 年前

    就像其他人所说的,您最好将其包装在using语句中,以强制调用Dispose方法。我相信这就是微软建议使用任何实现IDispose的方法,至少是基于他们的代码分析规则。

        7
  •  0
  •   supercat    15 年前

    IDisposable适用于这样的情况:当一个对象以某种方式改变了它自身之外的东西,而这种方式必须在某个点上在该对象消失之前被清除掉。临时文件的创建似乎符合条件。不过,有几点需要注意:

    1. 不幸的是,对于处理程序来说,没有好的方法来确定异常在运行时是否处于挂起状态。如果我有druthers,就会有一个IDisposable Ex接口,它继承了IDisposable,但也实现了Dispose(Ex as Exception)重载;这个接口的行为类似于IDisposable,只是Ex会作为内部异常传递给IDisposable本身可能引发的任何异常。事实上,没有这样的事情存在。因此,人们常常会面临这样一种不舒服的选择:要么吞下在处理时发生的异常,要么埋葬在处理之前发生的异常(并且可能首先预测了处理)。两种选择都很糟糕。
    2. 终结器必须避免执行任何可能阻塞或引发异常的操作。对于文件清理之类的事情,使用文件清理线程(对于一组类,而不是每个对象一个)可能会有帮助它等待终结器给它一个信号,然后清理文件。如果尝试清理文件块,则可能会阻止文件清理线程,但不会对整个应用程序造成灾难。

    我不特别喜欢定形器,重点应该放在使处理器工作上。

    推荐文章