异常处理最佳实践

4
我希望您能告诉我最佳的异常处理方式,因为在我的 Try 语句中,有很多验证,如果出现了一些 Exception ,那么我的 Catch 语句可以告诉我发生了什么,但是我如何知道哪个字段出现了 Exception示例代码
try
{
   // If I get a Exception when converting to number, 
   // I will understand the error 
   // but how could I know where in my `Try` statement was the error ?
   int valor = Convert.ToInt32(xmlnode[i].ChildNodes.Item(2).InnerText.Trim());
   // A Lot of another validations here
}
Catch(Exception e)
{
      this.LogInformation(e.Message);
}

3
对于所有的“Convert”,如果你不确定它们是有效的,你应该使用“TryParse”代替。例如,对于Int32:http://msdn.microsoft.com/en-us/library/f02979c7.aspx - Bolu
6个回答

3

如果您不确定值,请不要使用Convert.ToInt32。请改用Int32.TryParse:

int valor;
if (Int32.TryParse(xmlnode[i].ChildNodes.Item(2).InnerText.Trim(), out valor))
{
     // Worked! valor contains value
}
else
{
    // Not a valid Int32
}

此外,您不应该使用异常来捕捉验证错误。您的验证代码应计算值是否正确,而不是在错误时失败。验证类应该预期输入有效和无效数据。因为您预期输入无效数据,所以当它无效时,不应该捕获异常。
编写一个测试来检查数据是否有效,并返回true或false。几乎所有数值类型都有类似上述的TryParse方法。对于其他验证方法的自定义规则,请拟定一个规范,明确定义什么是有效和无效的输入,然后编写实现该规范的方法。

3

在将字符串转换为数字时,最好不要使用 Try-Catch。因此应该使用像 int.TryParse 这样的 TryParse 方法。

// note that here is also a possible error-source
string valorToken = xmlnode[i].ChildNodes.Item(2).InnerText.Trim(); 
int valor;
if(!int.TryParse(valorToken, out valor))
{
    // log this
}
// else valor was parsed correctly

除此之外,如果您想提供精确的错误信息,您必须使用多个try-catch或处理不同类型的异常(最一般的Exception类型必须是最后一个)。

但这只是一个例子,我有很多验证,不仅仅是 Convert.toInt32。我只想知道我的代码在 Catch 语句中停止的位置。 - Lucas_Santos

1
try..catch 放在循环内部。这样你就可以知道哪个项目导致了异常。
foreach(var xmlNode in nodes)
{
    try    
    {
       //
       int valor = Convert.ToInt32(xmlNode.ChildNodes.Item(2).InnerText.Trim());
       // A Lot of another validations here
    }
    catch(Exception e)
    {
       LogInformation(e.Message); // current item is xmlNode
       return;
    }
}

1
如果你尝试解析的值可能无法解析,即使是最遥远的可能性,那么它也不是一个异常情况,应该将其视为非异常情况。在这种情况下,有 TryParse 可以让你确定该值无法解析的情况。保留html标签。
int valor;
if(int.TryParse(xmlnode[i].ChildNodes.Item(2).InnerText.Trim(), out valor))
{
  // "valor" is sucessfully parsed
}
else
{
  // invalid parse - do something with that knowledge
}

但这只是一个例子,我有很多验证,不仅仅是 Convert.toInt32。我只想知道我的代码在 Catch 语句中停止的位置。 - Lucas_Santos
@Lucas_Santos - 我的回答也只是一个例子。你应该为你认为可能会失败的每件事情做类似的处理。 - Jamiec
你不需要使用int valor = 0来赋值,只需使用int valor进行声明即可! - user57508
@AndreasNiedermair - 这是一种严谨的写法。一个 int 隐式地被设置为零,我只是在明确表达。 - Jamiec
@Jamiec 顺便说一下,给out变量赋值总是表明代码的作者不清楚out参数的工作原理和用法... 对此我很抱歉,朋友,并没有恶意! - user57508
显示剩余3条评论

0

除非创建不同的异常(即不同的类),否则您需要使用不同的try catch来处理它。

通常可以这样做:

try
{
   // If I get a Exception when converting to number, 
   // I will understand the error 
   // but how could I know where in my `Try` statement was the error ?
   int valor = Convert.ToInt32(xmlnode[i].ChildNodes.Item(2).InnerText.Trim());
   // A Lot of another validations here
}
Catch(IOException ioe) {
      // Handle, log
}
Catch(ArgumentNullException ane) {
      // Handle, log
}
Catch(Exception e)
{
      // Handle, log and potentially rethrow
}

你也可以在 try 块中使用单独的 try-catch(这是我认为大多数人会做的),或者嵌套的 try-catch:

例如

// First block
try {
  // Convert here once
} catch (Exception ex) { 
 // Handle and log
}

// Second block
try {
  // Convert here once
} catch (Exception ex) { 
 // Handle and log
}

不确定这是否有所帮助。


你的标题提到了异常最佳实践。如果只是数字解析,那么我会选择Tobsey的答案。 - Yannis

0
try
{
}
catch (Exception ex)
{
    var stackTrace = new StackTrace(ex, true);

    var frame = stackTrace.GetFrame(0);

    var line = frame.GetFileLineNumber();

    var method = frame.GetMethod();
}

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