在Directory.Delete Directory.Exists有时返回true?

use*_*567 12 .net c# io

我有非常奇怪的行为.我有,

Directory.Delete(tempFolder, true);
if (Directory.Exists(tempFolder))
{
}
Run Code Online (Sandbox Code Playgroud)

有时Directory.Exists返回true.为什么?可能是探险家是开放的吗?

IIn*_*ble 20

Directory.Delete调用Windows API函数RemoveDirectory.观察到的行为记录在案:

RemoveDirectory函数在关闭时标记要删除的目录.因此,在关闭目录的最后一个句柄之前,不会删除该目录.

遗憾的是,.NET文档遗漏了这些信息.是否记录了静态Directory.Delete方法是否打开了目录句柄.同样,如果确实如此,则在手柄关闭时不会记录.

没有任何这些信息,您可以做的最好是轮询完成:

Directory.Delete(tempFolder, true);
while (Directory.Exists(tempFolder)) Thread.Sleep(0);
// At this point the directory has been removed from the filesystem
Run Code Online (Sandbox Code Playgroud)

尽管通常应该优先考虑轮询而不是事件,但是安装文件系统观察器对于这一点来说有点过头了.但请记住,此操作不是免费的,特别是在处理网络驱动器时.


更新:使用.NET的Reference Source,可以检查Directory.Delete的实现.此方法的第一个操作是迭代所有文件并删除它们.使用FindFirstFile/FindNextFile实现迭代.返回的句柄存储为SafeFindHandle,它是SafeHandle的具体子类.正如文档所指出的那样,通过具体的ReleaseHandle覆盖释放本机句柄.从一个(推迟的)关键终结器调用ReleaseHandle.由于最终确定是非确定性的,这解释了打开句柄,负责延迟目录删除.

但是,这些信息无助于找到比上述解决方案更好的解决方案(轮询完成).


这个问题的其他答案并未确定核心问题,而且最多只能巧合.BanksySan的回答添加了不相关的代码,这些代码引入了延迟以允许关闭打开句柄的时间.Byeni的回答更接近,但仍然是关闭的:当他谈到引用目录的对象时,他几乎指出了它.但是,引用该目录的对象称为句柄,即本机资源.本机资源在终结器中处理,GC.Collect()不运行终结器.这也似乎通过购买额外的时间来工作.

  • @hvd:根据[文档](http://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/safehandle.cs,56),仅在运行正常终结器之后才释放本机句柄。IDisposable模式不会运行终结器。 (2认同)

Ban*_*San 8

使用DirectoryInfo替代,并呼吁Refresh()这一点。

        var dir = new DirectoryInfo(tempFolder);
        dir.Delete();
        dir.Refresh();
Run Code Online (Sandbox Code Playgroud)

因为我们正在对目录执行许多操作,所以使用DirectoryInfo而不是Directory. 这可能解释了为什么没有Refresh()静态类,它用于一次性操作,因此永远不需要刷新。

如果可能值得Thread.Sleep(0)在刷新后添加一个以放弃线程并将其放在池的后面。还没有测试过,这只是一个沉思。