当前位置: 首页 > 编程语言 > C#

Dispose()方法中的异常应该如何处理?分享

时间:2023-04-10 15:48:01 C#

Dispose()方法中的异常应该如何处理?我想提供一个类来管理临时目录的创建和后续删除。理想情况下,我希望它在using块中可用,以确保无论我们如何离开块,目录都会被再次删除:staticvoidDoSomethingThatNeedsATemporaryDirectory(){using(vartempDir=newTemporaryDirectory()){//使用此处的目录...File.WriteAllText(Path.Combine(tempDir.Path,"example.txt"),"foonbarnbazn");//...if(SomeCondition){返回;}if(SomethingIsWrong){thrownewException("这是一个出错的例子。");}}//无论我们是否通过返回离开using块,//通过抛出和异常或只是通常丢弃末尾,//目录都会被TemporaryDirectory.Dispose删除。}创建目录没问题。问题是如何编写Dispose方法。当我们尝试删除一个目录时,我们可能会失败;例如,因为我们仍然有一个文件在其中打开。但是,如果我们允许异常传播,则可以屏蔽using块中发生的异常。特别是,如果在using块内部发生了异常,它可能是阻止我们删除目录的异常,但是如果我们屏蔽它,我们就失去了解决问题最有用的信息。似乎我们有四种选择:尝试删除目录时捕获并吞下任何异常。我们可能不知道我们还没有清理我们的临时目录。以某种方式检测在抛出异常时Dispose是否作为堆栈展开的一部分运行,如果是,则抑制IOException或抛出将IOException与抛出的任何其他异常组合在一起的异常。可能甚至不可能。(我想到这一点的部分原因是Python的上下文管理器可能在许多方面类似于.NET的IDisposable和C#的using语句。)永远不要抑制IOException来删除目录。如果在using块中抛出异常,我们将隐藏它,尽管它有很多机会比我们的IOException具有更多的诊断价值。放弃在Dispose方法中删除目录。此类用户必须负责请求删除目录。这似乎并不令人满意,因为创建类的很大一部分动机是为了减轻管理此类资源的负担。也许有另一种方法可以提供这种不容易搞砸的功能?其中一个选项显然是最好的吗?有没有更好的方法在用户友好的API中提供此功能?不要将其视为实现IDisposable的特殊类,而是根据正常的程序流程考虑它的外观:Directorydir=Directory.CreateDirectory(path);尝试{stringfileName=Path.Combine(path,"data.txt");File.WriteAllText(文件名,myData);上传文件(文件名);文件.删除(文件名);}最后{Directory.Delete(dir);这应该怎么做?这是完全相同的问题。您是将finally块的内容保持原样,从而可能阻止try块中发生的异常,还是将Directory.Delete包装在它自己的try-catch块中,吞下任何异常以防止阻塞原始异常?我认为没有任何正确答案——事实是,你只能有一个环境异常,所以你必须选择一个。但是,.NETFramework确实开创了一些先例;一个示例是WCF服务代理(ICommunicationObject)。如果您尝试处置有故障的通道,它将抛出异常并屏蔽堆栈中已有的任何异常。如果我没记错的话,TransactionScope也可以做同样的事情。当然,WCF中的这种行为一直是混淆的根源;如果它没有坏掉,大多数人实际上认为它很烦人。Google“WCFprocessingmask”,您就会明白我的意思。所以也许我们不应该总是尝试做像微软这样的事情。就个人而言,我认为Dispose永远不应该掩盖堆栈中已经存在的异常。using语句实际上是一个finally块,大多数时候(总是有边缘情况),您也不想在finally块中抛出(不是捕获)异常。原因只是调试;找到问题的根源是非常困难的——尤其是在您无法单步执行的生产环境中——当您甚至无法准确找出应用程序失败的位置时。我以前一直处于这个位置,我可以自信地说它会让你完全疯狂。我的建议是要么在Dispose中使用异常(当然要记录它),要么实际检查你是否已经因为异常而处于堆栈展开场景中,如果你知道你只是在吃后续异常,就把它们掩盖起来.后者的优点是除非你真的需要,否则不会吃掉异常;缺点是您已经在程序中引入了一些不确定的行为。又一个权衡。大多数人可能会选择前一个选项,并只隐藏finally(或using)中发生的任何异常。最后,我建议最好以FileStream为指导,这相当于选项3和4:关闭文件或删除Dispose方法中的目录,并允许作为该操作的一部分发生的任何异常冒泡(有效地吞下任何异常)但允许用户手动关闭资源而不需要使用组件来这样做。与MSDN的FileStream文档不同,我建议您广泛记录当用户选择using语句时可能发生的后果。这里要问的一个问题是调用者是否可以有效地处理异常。如果没有什么好用的(手动删除目录中使用过的文件?),最好记录错误并忘记它。为了涵盖这两种情况,为什么不使用两个构造函数(或构造函数的参数)?publicTemporaryDirectory():this(false){}publicTemporaryDirectory(boolthrowExceptionOnError){}然后您可以将决定推送给类的用户以确定适当的行为。一个常见的错误是无法删除目录,因为其中的文件仍在使用:您可以存储未删除的临时目录列表,并允许在程序关闭期间进行第二次明确的删除尝试(例如,TemporaryDirectory)。TidyUp()静态方法)。如果有问题的目录列表是非空的,代码可以强制垃圾收集处理未关闭的流。您不能依赖以某种方式删除目录的假设。其他一些进程/用户/任何可以在其中创建文件的东西。防病毒软件可能正忙于检查其中的文件等。你能做的最好的不仅是临时目录类,还有临时文件类(使用内部创建的临时目录块。临时文件类应该(尝试)删除Dispose上的相应文件。确保你至少有doneacleanupmethod...我会说从析构函数中为锁定文件抛出异常归结为使用异常报告预期结果-你不应该这样做。但是,如果发生其他事情,例如一个变量为空,可能确实存在错误,然后异常是有价值的。如果您希望锁定文件,并且您或您的调用者可能会帮助您,那么您需要在您的课程中包含该响应。如果您可以响应,在一次性调用中这样做),那么我将实现Dispose,以便在删除临时目录失败时不会抛出异常。更新:我会选择这个选项基于这样一个事实,即操作可能由于外部干扰而失败,例如来自另一个进程的锁,并且因为目录放在系统临时目录中,所以我看不到抛出的优势一个例外。对该异常的有效响应是什么?再次尝试删除该目录是不合理的,如果原因是来自另一个进程的锁,那就不在你的直接控制之下。要在using语句中使用该类型,您需要实现IDisposable模式。要创建目录本身,请使用Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)作为基础并使用新的Guid作为名称。以上就是C#学习教程:Dispose()方法中的异常应该如何处理?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: