C# 如果将泛型集合实例化为包含iDisposable项,这些项是否已被处置?

C# 如果将泛型集合实例化为包含iDisposable项,这些项是否已被处置?,c#,.net,idisposable,C#,.net,Idisposable,例如: Queue<System.Drawing.SolidBrush> brushQ = new Queue<System.Drawing.SolidBrush>(); ... brushQ.Clear(); Queue brushQ=new Queue(); ... brushQ.Clear(); 如果我没有显式地将每个项出列并分别处理它们,那么在调用Clear()时是否会处理剩余的项?队列何时被垃圾收集 假设答案是“不”,那么最佳做法是什么?您是否必须始终遍历队

例如:

Queue<System.Drawing.SolidBrush> brushQ = new Queue<System.Drawing.SolidBrush>();
...
brushQ.Clear();
Queue brushQ=new Queue();
...
brushQ.Clear();
如果我没有显式地将每个项出列并分别处理它们,那么在调用Clear()时是否会处理剩余的项?队列何时被垃圾收集

假设答案是“不”,那么最佳做法是什么?您是否必须始终遍历队列并处理每个项目

这可能会变得很糟糕,尤其是如果您必须尝试…最后在每个dispose周围,以防抛出异常

编辑

因此,一般收集的用户似乎有责任知道,如果这些项是一次性的(这意味着它们可能正在使用垃圾收集器无法清理的非托管资源),那么:

  • 从集合中删除项目时,请确保已对其进行了Dispose()处理
  • 不要调用Clear()。反复浏览 收集和处理每个 项目

  • 也许通用集合的文档应该提到这一点。

    您希望何时处置它们?集合如何知道其中是否有对对象的其他引用?

    泛型集合实际上不知道它们所包含的对象类型,因此调用Clear不会导致它们对项目调用Dispose()。一旦集合本身被处理掉,GC最终将处理掉它们,前提是其他任何东西都没有对其中一个项目的活动引用


    如果要确保在对集合调用Clear时调用对象的Dispose方法,则需要派生自己的集合并重写适当的方法,然后自己进行调用。

    正如其他人所说,这不会发生。但是,如果需要,您可以构建自己的扩展方法来处理它们。

    让我看看是否可以为此编写一个示例代码

    编辑:

    以下代码实现了IDisposable队列:

    class DisposableQueue<T>:Queue<T>,IDisposable where T:IDisposable
    
        #region IDisposable Members
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        public virtual void Dispose(bool disposing) {
            if (disposing) {
                foreach (T type in this) {
                    try
                    {
                        type.Dispose();
                    }
                    finally {/* In case of ObjectDisposedException*/}
                }
            }
        }
        #endregion
    }
    
    class DisposableQueue:Queue,IDisposable其中T:IDisposable
    #区域IDisposable成员
    公共空间处置()
    {
    处置(真实);
    总干事(本);
    }
    公共虚拟无效处置(bool处置){
    如果(处置){
    foreach(此处为T类型){
    尝试
    {
    type.Dispose();
    }
    最后{/*对于ObjectDisposedException*/}
    }
    }
    }
    #端区
    }
    
    “GC最终会处理它们…”据我所知,GC不会调用dispose。它将清理托管资源,但任何非托管资源都将保留。不正确。当GC最终开始释放内存时,如果该对象是IDisposable的,GC将处理它。除非brushQ.Clear()后面的行,否则您无法保证何时会发生这种情况;是GC.Collect();。关于这一点:(请参阅本页右侧面板中的“GC会调用IDisposable.Dispose吗?”。@Gwlosa:这不完全正确。如果对象实现IDisposable,只要没有其他引用,GC最终将收集它。如果仍然存在对该对象的活动引用,则不会收集该对象,因为它的容器已被收集。GC从不调用dispose。但是,如果您的类型有终结器,它将调用终结器。如果您正在为库设计自己的泛型队列派生,但如果t是否是一次性的,则不会调用终结器。您是否需要将您的设计分成两个版本:DisposableQueue和NondDisposableQueue?或者在运行时有没有办法确定T是否是一次性的?同样,这是假设没有人持有对您的项目的引用。正如在其他文章中提到的,我想对于通用队列来说,这不是一个好的假设。@mbeckish-正常队列是“不可分发”的。像if(type.GetType()==typeof(IDisposable))这样放置代码听起来不像是一种可靠的编程模式。@mbeckish-拥有IDisposable对象的全部目的是在停止使用资源时释放它们。这取决于你的代码来检查这些资源是否不再被使用。我同意。因此,似乎应该让队列的使用者承担这样的负担:在项目退出队列时进行处理,并在处理完队列后循环队列并处理剩余的项目。对于使用您的队列的开发人员来说,这可能会变得很糟糕。