为什么try块需要一个catch?

6

I have this code :

try 
{
    result.FirstName = nodes[myIdx]
        .Attributes["ows_FirstName"].Value;
} 
catch { }

在调用此函数之前,我不知道我要查找的属性是否存在(好老的SharePoint)。

因此,我想创建的代码的唯一线性方式就是这样。

try 
{
    result.FirstName = nodes[myIdx]
        .Attributes["ows_FirstName"]
        .Value;
} 
catch { }

try 
{
    result.LastName = nodes[myIdx]
        .Attributes["ows_LastName"]
        .Value;
} 
catch { }

现在我不需要这段代码的catch部分,最终产生了大量完全冗余的行。
为什么我不能只是这样做:
try 
{
    result.FirstName = nodes[myIdx]
        .Attributes["ows_FirstName"]
        .Value;
}

所以即使它没有被处理,为什么我们还要明确声明一个catch块呢?我相信这里有一个合理的原因但自己想不出来。

我知道异常处理的重要性,但是这里并没有什么特别之处,也没有任何我可以做(或需要做)来修复行为。


1
阅读此帖子 - CheGueVerra
@CheGueVerra - 不确定那与我的问题有什么关联? - Maxim Gershkovich
10个回答

7
它们并不是多余的 - 它们具有特定的目的。默认情况下,缺少 "catch" 块会将异常重新抛出到调用方法中。空的 "catch" 块基本上 "吞噬" 异常并让程序继续运行,无论是否抛出异常都不受影响;这通常是一个糟糕的做法。
“异常中没有任何异常”可能是真的,但这并不是唯一可能发生的异常。您应该处理此异常并适当处理其他任何异常。
例如-
如果 "nodes" 为空怎么办?如果 "myIdx" 超出了 "nodes" 数组的范围怎么办?这些条件都是异常的,您应该特别处理它们或让调用的程序处理它们并采取适当的措施。
你可能不能“修复”它,但你可能需要了解它。在这种情况下,程序的行为有什么不同?记录一条消息?引发警告?设置默认值?什么也不做可能是一个恰当的答案,但很可能对任何可能的异常都不是一个恰当的响应。

现在这是我看到的第一个合理的答案。我没有考虑到如果它是另一种异常类型而不是我正在忽略的异常会发生什么情况(尽管在我的示例中并不真正相关,但确实有道理)。感谢您的建议。 - Maxim Gershkovich

6

如果你想吞掉一个异常(即捕获它但什么都不做),你必须显式地这样做。

通常这是一种不好的做法,所以没有理由提供一个语法快捷方式。你一般要么:

  1. 以某种方式处理异常。这可能意味着:
a. 重试
b. 用更有意义的消息重新抛出它(保留内部异常)
c. 以其他方式完成
d. 记录它(尽管记录和重新抛出可能更好)
e. 其他

2. 让它冒泡(没有try,或只有try/finally)。


4
为什么不能只检查该项不是“null”?
if(nodes[myIdx].Attributes != null &&
   nodes[myIdx].Attributes["ows_FirstName"] != null) {
    /* ... your code ... */
}

或者:

if(nodes[myIdx].Attributes != null) {
   if(nodes[myIdx].Attributes["ows_FirstName"] != null) {
       /* ... your code ... */
   }
   if(nodes[myIdx].Attributes["ows_LastName"] != null) {
       /* ... your code ... */
   }
}

因为SharePoint XML Web服务具有令人惊叹的行为,即简单地省略空值属性而不是提供空值。 - Maxim Gershkovich
很遗憾,属性集合通常会包含至少一个值,因为你必须记住,通常你会返回至少几列。如果你只返回一列,这可能会起作用。希望这样说得清楚。 - Maxim Gershkovich
这个会起作用,因为你总是可以检查多列...我不是特别明白你的困惑在哪里... - Alex
抱歉,在回头检查后,你是正确的。你的解决方案确实有效。我道歉。 - Maxim Gershkovich

3

必须有另一种方式来检查该属性是否存在,不应该为了某些功能目的而使用异常处理,你的代码应该像这样:

try
{
    newstring = oldString.ToString();
}
catch{}

你需要做的是:

if(oldString != null)
{
    newstring = oldString;
}

记住,try catch是用来处理名为“异常”的事物的。

SharePoint XML WebServices会简单地省略空属性而不是提供空值。这意味着对于每个数据子集(即:每一行数据),我都需要运行并检查。在我看来,让异常发生(虽然有争议)更加实际。 - Maxim Gershkovich

2

这样做的原因可能是因为如果你无法处理异常,那么就不应该捕获异常。允许你使用try而没有对应的catch会导致更糟糕的实践。

至于你所引用的具体代码,你能在尝试访问索引器之前做一个空值检查吗?


请查看我对Simon Wang和Xander关于我的特定代码的回复。 - Maxim Gershkovich

1

try/catch 块专门设计用于捕获和处理应用程序中抛出的异常。

简单地吞噬异常通常是一个坏主意(即使你只是记录异常),必须明确地执行。


1

这是语言语法的一部分。你不能没有至少一个catch或者一个finally而使用try。不存在独立的try,只有try-catchtry-finallytry-catch-finally

如果你不打算处理异常(catch)或者确保一些后续代码始终运行(那就是finally),那么尝试执行某些代码就毫无意义。


他可能在问为什么这是语法。 - Matthew Flaschen

1

这个问题已经在这个帖子中得到了解答:C#: should all exceptions be caught

基本上,如果你要捕获它,那么你应该对它做些什么,否则就不要捕获它。在你的情况下,为什么不能先检查属性值是否存在呢?


1

看起来你正在使用SharePoint Web Services之一,所以返回类型应该是某种XmlElement? 我相信有一种方法可以检查属性是否存在,而不是抛出异常的方式更为经济实惠。

另外,你可能希望有一个辅助方法来封装检查和数据获取。


我不相信有一种方法可以使用XmlAttributeCollection进行检查(我已经查过了,但可能是错误的),但即使有,我仍然认为在某些情况下,这种语法也是合适的。 - Maxim Gershkovich

0

你不应该有空的 catch 块。这是糟糕的编程实践。

这让我想起了经典 ASP 中的 On Error Resume Next


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接