在某些情况下,我只想调用某个方法来完成一些工作,而不关心处理它可以抛出的所有特定异常。相反,我真正关心的是方法是否成功。
我将提供一个.NET / C#示例。假设我有一个我要复制的文件,我真正关心的是复制操作是否成功。如果复制失败,我不在乎特定异常是FileNotFoundException还是IOException“没有足够的磁盘空间”异常或其他...在这种情况下我的应用程序将正常运行,因为此操作并不重要。
所以如何实现这个想法是:
try
{
// try
System.IO.File.Copy(strFile, strFile + ".new");
}
catch (Exception ex)
{
// if critical exception then rethrow
if (IsCritical(ex))
throw;
// else just log and swallow...
Console.WriteLine("Failed to copy the file: " + ex.Message);
}
其中IsCritical(Exception ex)是辅助方法,定义为:
public static bool IsCritical(Exception ex)
{
if (ex is OutOfMemoryException) return true;
if (ex is AppDomainUnloadedException) return true;
if (ex is BadImageFormatException) return true;
if (ex is CannotUnloadAppDomainException) return true;
if (ex is ExecutionEngineException) return true;
if (ex is InvalidProgramException) return true;
if (ex is System.Threading.ThreadAbortException)
return true;
return false;
}
此问题基于以下文章:Exception Handling in C# with the "Do Not Catch Exceptions That You Cannot Handle" rule in mind
这个想法是遵循异常处理最佳实践的主要规则: - 不要在没有重新抛出的情况下捕获一般异常 - 只捕获您知道如何处理的异常 - (在这种情况下,我希望以相同的方式处理它们...通过记录并继续使用应用程序逻辑)。
对于给定的场景,这是一个很好的方法吗?如果没有,为什么以及什么是更好的事情呢?
答案 0 :(得分:21)
通常建议不要吞下异常的原因是它可以隐藏错误。例如,除了执行File.Copy
之外,您正在执行其他操作:您也在进行字符串处理(strFile + ".new"
)。这不能扔(除了OOM),但如果计算更复杂,你可能隐藏了一个错误。
在这种情况下,您应该将所有计算移出try-block。然后可以吞下任何异常。我养成了记录它们的习惯,以防万一我仍然犯了一个错误,尽管小心翼翼。
不必要地吞下的规则是保护开发人员免受他自己的错误。如果您有理由确定一切正常,那么您不需要遵守规则。
答案 1 :(得分:8)
这条线让我有点担心......
如果复制失败,我不在乎特定异常是FileNotFoundException还是IOException“没有足够的磁盘空间”异常或其他什么
与FNF异常不一样,但更多的是“没有足够的磁盘空间”等 - 这些是您可能不想忽略的异常。原因是,如果没有足够的磁盘空间,理论上,您的应用最终会失败 。这实际上是你不应该捕获一般异常的主要原因之一,因为你有效地掩盖了这些更大的问题。
更一般地说,并且更具体地回答你的问题,如果您确信它不会对您的应用产生任何重大影响,并且如前所述(并且我 - 有充分理由 - 不会掩盖任何更大/更严重的问题。
答案 2 :(得分:6)
在特定情况下可以吞下特定的例外,但在实践中它取决于用例。
我建议处理异常,可以处理并使用AppDomain.UnhandledException事件处理未处理的异常,并告知用户发生了什么。
从调试的角度来看,只要您有权访问代码就没那么重要,因为您可以在Visual Studio中启用所有常见的运行时异常。 (调试 - >例外 - >公共语言运行时例外 - >选中左侧复选框)
我永远不会依赖关键异常列表,因为你不知道列表是否完整。
答案 3 :(得分:0)
您可以为同一次尝试添加多个catch语句:
try
{
//code here
}
catch (FileNotFoundException ex1)
{
//Do whatever you want
}
catch (IOException ex2)
{
//Do whatever you want
}
我建议处理你不认为是关键的例外以及剩下的所有例外
只做一个catch (Exception er){throw ;}
另外,仅仅因为这两个特定的例外就足以捕获IOException
,因为IOException
是FileNotFountException
的父类
答案 4 :(得分:0)
我想你自己回答了你的问题。这完全取决于您的业务逻辑。但一般来说,如果我只是按照他们的特定类型“吞下”异常,那么你再次以另一种方式做到了。
答案 5 :(得分:0)
我倾向于说任何来自您自己未编写的代码的异常应该被视为关键异常,因为这意味着抛出错误的系统很可能是处于未定义状态,因此无法保证您在该系统上尝试的任何后续操作都能成功。
因此,我可能会做类似的事情:
try
{
System.IO.File.Copy(strFile, strFile + ".new");
//MyLibrary throws exception clases I defined so I know what they are all about
MyLibrary.SomeClass.DoSomething(strFile);
}
catch(ExceptionTypeIDefinedInMyLibraryWhichIKnowICanSafelyIgnore iex)
{
Console.WriteLine("Not to worry: "+ iex.Message);
}
catch (Exception ex)
{
//This absolute is not something I can handle. Log it and throw.
Log(ex); throw;
}
通过这种方式,您无法忽略关键异常,并且您只能从您自己的子系统中抛出特定类型的异常,因为您可以控制它们抛出的内容。
但是,如果你真的想要遵循你演示的模式,我会倾向于转过头来处理你知道你可以处理的异常,然后扔掉其他所有的东西。
这样,当一个新的OhMyGodThereAreZombiesInTheServer
异常被添加到BCL时你就不会被烧掉,你永远不会知道,它可能会发生......
即
try
{
// try
System.IO.File.Copy(strFile, strFile + ".new");
}
catch (Exception ex)
{
// if critical exception then rethrow
if (ICanHandleThis(ex))
{
Console.WriteLine("Failed to copy the file: " + ex.Message);
}
else
{
//step aside and let Dr McNinja deal with it
throw;
}
}
public static bool ICanHandleThis(Exception ex)
{
//I don't care about these exceptions, they aren't critical
//to my application for some reason.
return (ex is SomeTrivialExceptionTypeIDontCareAbout
|| ex is SomeOtherIgnorableExceptionType);
}
答案 6 :(得分:0)
吞下异常是可以的,如果您希望程序不可欺骗并且管理员讨厌您。
您至少需要以较低的日志级别debug
,trace
,fine
或其他级别记录例外。
这将有助于调试问题,了解程序的工作方式或未发生某些事情的原因。
唯一可以被吞噬的异常是对应用程序绝对没有影响的异常(例如,睡眠中断异常)。请参见此nice article。
现在在您的示例中,您并没有完全吞下异常,而是在丢弃堆栈跟踪时打印消息。
只需确保异常消息包含有关复制源和目标的信息,以便用户可以对其进行调试。另外,取决于您的应用程序,了解应用程序代码的哪一部分正在执行复制可能会很有用。有时可能需要。