Try/Catch — 我怎么知道在 odd/complex 情况下要捕获什么?

Try/Catch — How do I know what to catch in odd/complex cases?

我知道为什么我不应该像这样使用开放的 catch 块:

int x = 0;
try
{
    x = GetXFromSomeplaceThatCanFail();
}
catch //Possibly (Exception) or (Exception e)
{
    //Ignore The Failure Because We Don't Care If It Fails
}
if (x != 0) //Yes I know I can use finally blocks to do something similar, but this is just an example case
{
    //Do Things With x
}

我完全知道这会 "swallow" 诸如 OutOfMemoryException 之类的事情,这是不好的做法,可能会导致未检测到的 failures/subtle 错误,这些错误 很糟糕东西.

这就是为什么我要检查我的代码并确保没有这样的事情。通常你会去 try 块中使用的任何内容的文档并捕获预期的异常,或者知道某些操作会产生某些异常(比如访问带有索引的数组时的 IndexOutOfRangeException 等)。

但是,没有文档可以检查奇怪的情况以查看可能抛出的异常(或者很难找到)。我自己项目中的一个特定案例(变量名通用化和代码简化)使用动态类型获取字符串字段 仅当它存在时 否则通过提供 "N/A" 优雅地失败作为结果。再次提醒您,我知道这是错误的代码:

string theString = "Some Old Value From Previous Run/etc.";
try
{
    theString = (placeWhereValuesComeFrom as dynamic).TheString;
}
catch
{
    theString = "N/A";
}

在此上下文中,placeWhereValuesComeFrom 继承自不(也不应该)提供 TheString 的 BaseClass。

我意识到我可以创建一个提供 TheString 并继承自 BaseClass 的中间体 class,然后从中继承。但是,动态解决方案实施起来非常快并且效果很好。除非针对我的特定场景提出更好的解决方案,否则我计划添加一个中间 class 并只使相关的 class 继承它,然后像这样测试:

theString = placeWhereValuesComeFrom is Subclass ? ((Subclass)placeWhereValuesComeFrom).TheString : "N/A";

但是,假设我不想出于任何原因重构使用中间件 class,我应该在这里做什么?我怎样才能发现我应该在 catch 块中安全地忽略哪些可能的异常?如果没有真正的方法来 "look up" 可以抛出哪些异常,那么其他类似情况呢?

您在这里应该处理的唯一异常是运行时绑定失败;当动态对象未实现 TheString 时。抛出的异常类型为Microsoft.System.CSharp.RuntimeBinder.RuntimeBinderException.

所以你的代码应该是这样的:

try
{
    str = myDynamicObject.TheString;
}
catch (Microsoft.System.CSharp.RuntimeBinder.RuntimeBinderException)
{
    //Binding failure
    str = "N/A"
}
catch ( ... //exceptions you know TheString can throw, if any...)
{
    //Handle
}
// any other exception you don't know how To handle...don't handle it