我刚刚看到一个关于try-catch的问题,哪些人(包括Jon Skeet)认为空catch块是一个非常糟糕的主意?为什么呢?在任何情况下,空接点都不是错误的设计决策吗?
我的意思是,例如,有时你想从某个地方(webservice,数据库)获得一些额外的信息,你真的不关心你是否会得到这个信息。所以你试着获取它,如果发生了什么,没关系,我只会添加一个“catch (Exception ignored){}”,仅此而已
我刚刚看到一个关于try-catch的问题,哪些人(包括Jon Skeet)认为空catch块是一个非常糟糕的主意?为什么呢?在任何情况下,空接点都不是错误的设计决策吗?
我的意思是,例如,有时你想从某个地方(webservice,数据库)获得一些额外的信息,你真的不关心你是否会得到这个信息。所以你试着获取它,如果发生了什么,没关系,我只会添加一个“catch (Exception ignored){}”,仅此而已
当前回答
因为如果抛出异常,您将永远不会看到它——默默地失败是最糟糕的选择——您将得到错误的行为,而且不知道它发生在哪里。至少在那里放一条日志消息!即使是“不可能发生”的事情!
其他回答
这与“不要使用异常来控制程序流”和“只在异常情况下使用异常”是密切相关的。如果执行了这些操作,那么只有在出现问题时才会出现异常。如果出现了问题,你也不想默默地失败。在不需要处理问题的罕见异常中,您至少应该记录异常,以防异常不再是异常。比失败更糟糕的是默默的失败。
通常,您应该只捕获您实际可以处理的异常。这意味着在捕获异常时要尽可能具体。捕获所有异常很少是一个好主意,而忽略所有异常几乎总是一个非常糟糕的主意。
我只能想到一些空catch块具有有意义的用途的实例。如果您正在捕获的任何特定异常都是通过重新尝试操作来“处理”的,则不需要在catch块中做任何事情。但是,记录发生异常的事实仍然是一个好主意。
另一个例子:CLR 2.0改变了终结器线程上未处理异常的处理方式。在2.0之前,允许流程在这种情况下存活。在当前CLR中,如果终止器线程上出现未处理的异常,进程将被终止。
Keep in mind that you should only implement a finalizer if you really need one and even then you should do a little as possible in the finalizer. But if whatever work your finalizer must do could throw an exception, you need to pick between the lesser of two evils. Do you want to shut down the application due to the unhandled exception? Or do you want to proceed in a more or less undefined state? At least in theory the latter may be the lesser of two evils in some cases. In those case the empty catch block would prevent the process from being terminated.
在极少数情况下,这样做是合理的。在Python中,你经常会看到这样的结构:
try:
result = foo()
except ValueError:
result = None
所以它可能是OK的(取决于你的应用程序):
result = bar()
if result == None:
try:
result = foo()
except ValueError:
pass # Python pass is equivalent to { } in curly-brace languages
# Now result == None if bar() returned None *and* foo() failed
在最近的一个. net项目中,我必须编写代码来枚举插件dll,以查找实现特定接口的类。相关的代码(在VB中。NET,对不起)是:
For Each dllFile As String In dllFiles
Try
' Try to load the DLL as a .NET Assembly
Dim dll As Assembly = Assembly.LoadFile(dllFile)
' Loop through the classes in the DLL
For Each cls As Type In dll.GetExportedTypes()
' Does this class implement the interface?
If interfaceType.IsAssignableFrom(cls) Then
' ... more code here ...
End If
Next
Catch ex As Exception
' Unable to load the Assembly or enumerate types -- just ignore
End Try
Next
尽管在这种情况下,我承认在某个地方记录失败可能是一种改进。
在某些情况下,您可能会使用它们,但它们应该非常不频繁。我可能会使用它的情况包括:
异常日志记录;根据上下文的不同,您可能希望发布一个未处理的异常或消息。 循环技术情况,如渲染或声音处理或列表框回调,行为本身将演示问题,抛出异常将只是阻碍,记录异常可能只会导致1000个“失败到XXX”消息。 不能失败的程序,尽管它们至少应该记录一些东西。
对于大多数winforms应用程序,我发现对于每个用户输入都有一个try语句就足够了。我使用以下方法:(AlertBox只是一个快速的消息框。显示包装)
public static bool TryAction(Action pAction)
{
try { pAction(); return true; }
catch (Exception exception)
{
LogException(exception);
return false;
}
}
public static bool TryActionQuietly(Action pAction)
{
try { pAction(); return true; }
catch(Exception exception)
{
LogExceptionQuietly(exception);
return false;
}
}
public static void LogException(Exception pException)
{
try
{
AlertBox(pException, true);
LogExceptionQuietly(pException);
}
catch { }
}
public static void LogExceptionQuietly(Exception pException)
{
try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
}
然后每个事件处理程序都可以这样做:
private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
{
EditorDefines.TryAction(Dispose);
}
or
private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
{
EditorDefines.TryActionQuietly(() => Render(pEventArgs));
}
理论上,您可以使用tryactionsilent,它可能更适合呈现调用,这样异常就不会生成无穷无尽的消息。
我的意思是,例如,有时你想从某个地方(webservice,数据库)获得一些额外的信息,你真的不关心你是否会得到这个信息。所以你试着获取它,如果发生了什么,没关系,我只会添加一个“catch (Exception ignored){}”,仅此而已
因此,以您的示例为例,在这种情况下这是一个坏主意,因为您捕获并忽略了所有异常。如果您只捕获einfofromirrelevance sourcenotavailable并忽略它,那是可以的,但您没有。您还忽略了ENetworkIsDown,它可能重要,也可能不重要。你忽略了enetworkcardhasmelting和efpuhasdecisidthatoneplusoneisseventeen,它们几乎肯定是重要的。
如果将空捕获块设置为只捕获(并忽略)您知道不重要的某些类型的异常,则空捕获块不是问题。在这种情况下,最好压制并默默地忽略所有异常,而不停下来先检查它们是否是预期的/正常的/不相关的,这种情况非常罕见。