C# 在dispose模式中垃圾收集文件类型的正确位置

C# 在dispose模式中垃圾收集文件类型的正确位置,c#,dispose,unmanaged,C#,Dispose,Unmanaged,现在,我的同事们就C#文件类型需要在哪里处理展开了争论。() 查看下面的代码,当前File.Delete位于if(disposing)部分,在该部分中,它被考虑用于托管对象。有些人认为它需要在循环之外,并且需要成为非托管对象的位置 ~someService() => Dispose(false); public void Dispose() { Dispose(true); GC.SuppressFinalize(this); GC.Collect(); } b

现在,我的同事们就C#文件类型需要在哪里处理展开了争论。()

查看下面的代码,当前File.Delete位于if(disposing)部分,在该部分中,它被考虑用于托管对象。有些人认为它需要在循环之外,并且需要成为非托管对象的位置

~someService() => Dispose(false);

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
    GC.Collect();
}

bool disposed = false;
protected virtual void Dispose(bool disposing)
{
    if (disposed)
    {
        return;
    }

    if (disposing)
    {
        // Dispose managed state (managed objects).
        tempFilePaths?.ToList().ForEach(f =>
        {
            if (File.Exists(f))
            {
                File.Delete(f);
            }
        });

        this._engine?.Dispose();
    }

    // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
    // TODO: set large fields to null.
    this._fields = null;

    disposed = true;
}

只要仔细阅读
IDisposable
模式,就可以理解这些“部分”的含义以及执行时间

TL;DR
if(disposing)
块之外,您不会使用对托管对象的任何现有引用。在您的示例中,
tempfilepath
似乎是
IEnumerable
类型的字段/属性,该类型是托管对象(现有引用)。因此,访问/使用它的唯一正确位置是
if(disposing)
块内部

原因
if(disposing)
之外的代码在调用public
Dispose()
方法和由终结器调用时运行

将在特殊终结器线程上调用终结器。不能保证在调用终结器时,
tempfilepath
完全可用。它可能已经被GC收集,尽管对象引用由类实例持有。这就是终结者的工作方式

如果您想在与团队讨论时了解更多背景和更多论据,请仔细阅读Eric Lippert(前C#编译器团队成员)关于终结器的以下博文:



归根结底,当对象没有被显式地释放,对象不再被使用,并且如果文件是否应该被删除,GC将调用终结器。如果在任何情况下都应该删除,则将其放在If块之外。但是,终结器应该避免做繁重的工作,因为GC是单线程的,速度慢的终结器会减慢GC的工作。另一个问题是,您不应该调用
GC.Collect
。让GC在有时间时处理清理。但另一方面,我不希望通过将托管对象置于if(disposing)之外来看到ObjectDisposedException。如果需要快速释放内存,那么GC.Collect似乎是必要的,所以我想知道为什么永远不应该调用它。谢谢。为什么需要快速收集内存?当内存压力较高时,GC将自动收集它。垃圾收集很昂贵。因此,在处理此类对象时随时触发它,不仅是为了释放对象本身,而且是为了释放进程中所有不需要的对象,可能会对应用程序性能产生负面影响。此外,它还违反了单一责任原则,因为提取服务不应该关注进程内存管理。它确实是特定于应用程序的,但当前设计的问题是,分配给前一个任务的内存确实会阻止下一个任务完成工作,因为数据会立即进入可能导致占用大量内存,需要删除。但是让我搜索更多关于GC.Collect的副作用的内容,谢谢。我想说的是,你不应该删除终结器中的文件,因为它会对你的应用程序的性能产生负面影响,终结器应该很快,所以它绝对不应该在终结器中执行。但如果由于某种原因,
Dispose
未被调用,文件将不会被删除。但是你也不能依赖finalizer,所以我认为最好的方法是删除
Dispose(true)
中的文件,并为特殊情况提供备份策略(例如,如果你保证只运行一个应用实例,则在应用启动时执行清理)。OP想要删除文件,他不处理
tempfilepath
@GuruStron,OP访问已经很危险的
tempfilepath
集合。收集内容发生了什么并不重要。简单地访问一个死对象可能会导致终结器崩溃(操作系统会立即终止应用程序)。是的。如果未调用
Dispose
,仍然会保留未清除文件的问题。这是正确的。但是使用
Dispose
清理非一次性资源是不正确的设计。@dymanoid,您将哪个资源称为非一次性资源?如果Dispose不是正确的位置,那么应该在哪里编写代码来清理非一次性资源?