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
我知道为什么我不应该像这样使用开放的 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