Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 临时解压-这是IDisposable接口的有效使用吗?_C#_.net_Idisposable - Fatal编程技术网

C# 临时解压-这是IDisposable接口的有效使用吗?

C# 临时解压-这是IDisposable接口的有效使用吗?,c#,.net,idisposable,C#,.net,Idisposable,我想封装解压缩zip文件的过程,使文件可供使用,然后在不再需要时自动清理它们。我用一个实现IDisposable接口的类实现了这一点,这样我就可以用“using”来实例化它,当超出范围时,文件将被清理,无需专门删除文件。因此,可以使用类TempUnzip: static void AccessZipFileContents(string zipFilePath) { using (var temp = new TempUnzip(zipFilePath)

我想封装解压缩zip文件的过程,使文件可供使用,然后在不再需要时自动清理它们。我用一个实现IDisposable接口的类实现了这一点,这样我就可以用“using”来实例化它,当超出范围时,文件将被清理,无需专门删除文件。因此,可以使用类
TempUnzip

    static void AccessZipFileContents(string zipFilePath)
    {
        using (var temp = new TempUnzip(zipFilePath)
        {
            var tempPath = temp.TempPath;
            if (tempPath != null)
            {
                // read/use the files in tempPath
            }
        } // files automatically get deleted when it goes out of scope! Woohoo!
    }
下面是TempUnzip类的实现:

using System.IO;
using System.IO.Compression;
public class TempUnzip : IDisposable
{
    public TempUnzip(string zipFilePath)
    {
        try
        {
            var tempFolderName = Path.GetRandomFileName();
            var tempFolder = Path.GetTempPath();
            var tempPath = Path.Combine(tempFolder, tempFolderName);
            Directory.CreateDirectory(tempPath);
            ZipFile.ExtractToDirectory(zipFilePath, tempPath);
            TempPath = tempPath;
        }
        catch (Exception) { TempPath = null; }
    }

    public readonly string TempPath;

    public void Dispose()
    {
        try
        {
            if (TempPath != null)
                Directory.Delete(TempPath);
        }
        catch (Exception) { }
    }
}

这是IDisposable的有效使用吗?

  • 如果是,我需要实施吗

  • 如果没有,是否有更好的方法来封装文件的创建和销毁,使其与对象的生命周期相关联,或者我应该完全避免这种情况?


在这种情况下,我想说这是IDisposable的一个很好的例子,如果没有立即调用Dispose,说明您已经使用完它,那么这不是世界末日,快速调用同一个zip文件不会导致异常,因为您每次都使用独特的临时文件夹;我能看到的唯一问题是,如果磁盘空间真的很紧,您可能希望公开delete文件夹作为一种方法,允许直接调用该选项,然后使用Dispose来清理所有情况


注意:在本例中,您可能需要调用Directory.Delete(TempPath,true);因为如果文件夹不是空的,您调用的方法将抛出IOException(您捕获的内容将隐藏)-请参见

这是IDisposable的有效使用吗?

从:

提供释放非托管资源的机制

本地磁盘上的文件当然是非托管资源。因此,这种使用符合
IDisposable
的规定目的

如果是,我需要实现完整的标准IDisposable模式吗?

你可以。需要考虑有关终结器的常见警告,但您已经链接到这些警告。当然不会痛的

如果没有,是否有更好的方法来封装文件的创建和销毁,使其与对象的生命周期相关联,或者我应该完全避免这种情况?

我也喜欢用函数方法解决这类问题。这将使您的示例看起来像这样:

static void AccessZipFileContents(string zipFilePath)
{
    ZipManager.RunWithZipExtracted(zipFilePath, (string tempPath) =>
    {
        if (tempPath != null)
        {
            // read/use the files in tempPath
        }
    } // files automatically get deleted when it goes out of scope! Woohoo!
}

//from ZipManager.cs...
static void RunWithZipExtracted(string zipLocation, Action<string> toRun)
{
    var tempPath = CalculateTempPath();
    try
    {
        ExtractZip(zipLocation, tempPath);
        toRun(tempPath);
    }
    finally
    {
        DeleteFolder(tempPath);
    }
 } //private methods left as exercise for the reader
静态无效访问ZipFileContents(字符串zipFilePath)
{
ZipManager.RunWithZipExtracted(zipFilePath,(字符串tempPath)=>
{
if(tempPath!=null)
{
//读取/使用tempPath中的文件
}
}//文件超出范围时会自动删除!呜呜!
}
//从ZipManager.cs。。。
静态void RunWithZipExtracted(字符串zipLocation、操作toRun)
{
var tempPath=CalculateTempPath();
尝试
{
ExtractZip(zipLocation,tempPath);
托伦(临时路径);
}
最后
{
删除文件夹(临时路径);
}
}//留给读者作为练习的私有方法

这样的模式避免了“如果他们不调用Dispose怎么办?”完全如此。

在这种情况下,拥有终结器可能是一个好主意,但MS模式是基于公共对象拥有终结器的想法,这几乎总是一个坏主意。相反,需要基于终结的清理的资源应该封装在私人持有的对象中,这些对象的引用永远不会公开由于内部对象是私有的,因此它们不需要使用IDisposable模式,而是可以按照最适合需求的方式进行设计


因为多次尝试关闭文件句柄可能会造成灾难性后果,而且当其他代码正在使用对象时(甚至在对象上执行
Dispose
),终结器可能会执行(尽管很少),编写一个健壮的类可能很困难。出现的一个棘手问题是,文件访问可以阻止,但终结器操作不应该阻止。可以通过创建一个线程来解决这个问题,该线程的目的是等待文件被关闭并删除,然后关闭并删除该文件。即使尝试删除文件e被阻止,其他终结器操作可能会快速继续。不幸的是,急于创建线程以允许基于终结器的安全清理很容易浪费资源,但在终结器中创建线程似乎是一项过重的任务。我不知道最好的解决方案是什么。

Personal Ly我不反对将
IDisposable
用于生命周期有限、时间终点可控和相关清理的事物。在这种特殊情况下,我可能会尝试将其拆分为一个处理临时文件夹的事物和一个进行解压缩的事物,而不是尝试将两者结合起来。换句话说s、 我可能会使用IDisposable和delete目录等将临时路径片段分离到一个
TemporaryFolder
类,然后将该文件夹的路径传递给一个普通的解压例程,该例程对该文件夹的“临时”部分一无所知。您违反了IDisposable约定。调用Dispose()是可选的,在很多情况下,不调用它是完全合法的,并且没有不良副作用。在您的代码中不是这样的,它没有终结器。如果您愿意,您可以滥用它,但是您必须编写一本手册来说服客户端程序员始终使用它。Hans,
IDisposable 说“你应该”,而不是“你可以”,但你是对的,这并不能保证你会做到。还有一个重要的优先事项是你不应该离开