C# Try/Catch—;我如何知道在奇数/复杂的情况下要抓住什么?

C# Try/Catch—;我如何知道在奇数/复杂的情况下要抓住什么?,c#,exception,exception-handling,catch-block,dynamictype,C#,Exception,Exception Handling,Catch Block,Dynamictype,我知道为什么我不应该像这样使用开放式挡块: 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 some

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

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
}
我完全知道这会“吞下”像OutOfMemoryException这样的东西,这是一种不好的做法,可能会导致未检测到的失败/细微错误,这是非常糟糕的事情

这就是为什么我要检查我的代码,并确保没有类似的事情。通常,您会转到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 = placeWhereValuesComeFrom is Subclass ? ((Subclass)placeWhereValuesComeFrom).TheString : "N/A";

然而,假设我不想出于任何原因重构以使用中间类,那么我应该在这里做什么呢?如何发现在catch块中应该安全忽略哪些可能的异常?对于其他类似的情况,如果没有真正的方法来“查找”可以抛出哪些异常,该怎么办?

这里您应该处理的唯一异常是运行时绑定失败;当动态对象未实现字符串时。引发的异常类型为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

通常,如果您能够处理异常,因为您知道如何从中恢复,那么您可以捕获它(并将其注销)。如果你不知道如何从异常中恢复,那么你应该让你的应用程序崩溃,并记录崩溃的所有细节。你不会“发现”哪些异常应该被忽略。相反,您只捕获实际编写代码来处理的异常。如果您不知道异常是什么,那么根据定义,您无法处理它们,也不应该捕获它们。我知道,如果强制动态没有相关字段,它将抛出异常。我想处理这个例外。但是,我不知道异常类型是什么,动态类型的文档也没有告诉我。在其他情况下,这也适用——在这些情况下,我们做了什么?您要么找到更好的文档(文档应该总是指出方法抛出的调用方可处理的异常),要么测试它以查看(这很糟糕,因为它很脆弱,并且在库发生更改时会被破坏,但任何其他基于反射的方法也是如此)。捕获异常时,在
(exception ex){ex.GetType().Name}
中,将为该异常提供最派生的类名!!这是解决上述特定情况的有效代码,但不能解决文档没有告诉您任何信息,您也不想手动检查故障的一般情况。@Yushatak那么我只是认为您问题的前提是错误的。您应该捕获您知道如何处理的异常,而不是其他异常。如果您不知道可能会遇到哪些异常,那么您肯定不知道如何处理它们。要么你使用的是一个记录得很糟糕的库(使用另一个库),要么你使用的是一个你不完全理解的库(研究它,然后对你的代码进行彻底的单元测试)。如果文档没有告诉您,您要么自己调查,要么选择其他方法。。我希望您可以突出显示代码,然后右键单击“列出可能的异常”选项,该选项将逐层运行代码,并枚举可能引发的异常(如果您单击其中一个,它将显示找到它的位置)。在这一点上,您还可以放置一些按钮,用于为所选或所有可能的异常添加处理程序,以便以自己的方式正确处理每个异常。