在处理C#异常时,如何压缩大量的小Try-Catch块?

8

在我的对象转换代码中,我有大量的:

    try
    {
        NativeObject.Property1= int.Parse(TextObject.Property1);
    }
    catch (Exception e)
    {
        Trace.WriteLineIf(ConverterSwitch.TraceVerbose, e);
    }
    try
    {
        NativeObject.Property2= DateTime.Parse(TextObject.Property2);
    }
    catch (Exception e)
    {
        Trace.WriteLineIf(ConverterSwitch.TraceVerbose, e);
    }

等等……我不希望由于某个属性的问题而导致所有转换失败,因此我不能把所有内容都放在一个 try 块中,但是我需要记录如果有任何失败并继续执行..
有没有一种方法可以简化所有这些 try catch 的内容?

遗憾的是我们不能像写 C# 代码一样:

try
{
    int num = int.Parse("3");
    decimal num2 = decimal.Parse("3.4");
}
catch (Exception e)
{
    Trace.Write(e);
    continue; //continue execution from the point we left. (line 2)
}

2
如果你转向VB.NET,你可以使用On Error Resume Next :-) - Cody Gray
1
某处,一位VB6/VBA开发人员正在嘲笑你。从未想过会有人渴望使用“On error resume next”。 - JohnFx
2
@Cody:哦,天啊。哦,不要啊。拜托,不要。 - cdhowie
1
你应该使用 tryParse 并验证你的数据。如果数据有可能无效,它应该被验证,异常处理非常低效。异常实际上会导致 CPU 中断。这意味着数千个周期的时间浪费。 - Bengie
有趣的事情,我刚刚花了5分钟想知道为什么我的continue;语句在foreach循环中无法编译,我完全忘记了我正在使用Try(()=>{;})匿名方法而不是通常的Try块 :-) - Alex Burtsev
显示剩余2条评论
6个回答

13

当可用时,你可以使用TryParse方法。以下是解析Int32值的示例代码。

   private static void TryToParse(string value)
   {
      int number;
      bool result = Int32.TryParse(value, out number);
      if (result)
      {
         Console.WriteLine("Converted '{0}' to {1}.", value, number);         
      }
      else
      {
         if (value == null) value = ""; 
         Console.WriteLine("Attempted conversion of '{0}' failed.", value);
      }
   }

2
是的,这是正确的方法,假设问题中的示例代码准确地描述了您想要通过这些嵌套的Try-Catch块实现的内容。尽可能预防异常而不是尝试处理它们总是更好的选择。 - Cody Gray
1
好的回答!+1,因为解决了实际问题,而不是回答一个关于解决方法的问题。 - JohnFx
+1 TryParse 是更好的选择,如果你想忽略解析错误的话。 - juharr
@BobBlack:我的真实代码并不像我写的那么简单,所以使用Action<>的一般方法对我更好。 - Alex Burtsev
我正要建议这个,但你比我先说了 :) - Piers Myers
我认为这个答案得到了太多的赞,因为它并没有真正回答问题。我完全同意当可用时,TryParse方法比try/catch更好,但问题是关于压缩代码的,而这个回复并没有提供解决方案。也许将建议将转换封装在单独的方法中的回复与此结合起来会是最好的答案。 - Florin Dumitrescu

11

不行,但你可以这样做:

private static void ExecuteAndCatchException(Action action)
{
  try 
  { 
    action();
  } 
  catch (Exception e) 
  { 
    Trace.Write(e); 
  } 
}

然后

ExecuteAndCatchException(() => NativeObject.Property1 = int.Parse(TextObject.Property1)); 
ExecuteAndCatchException(() => NativeObject.Property2 = DateTime.Parse(TextObject.Property2));

1
真遗憾,这个因为打错字而无法编译... :P - cdhowie
@cdhowie,糟糕,我没有尝试编译它,哪里有错别字? - vc 74
@vc:Action(); -- 另外,由于没有使用this,所以该方法应该是静态的。 - cdhowie

4
你可以这样做:
private static void Attempt(Action action)
{
    try { action(); }
    catch (Exception e) {
        Trace.WriteLineIf(ConverterSwitch.TraceVerbose, e);
    }
}

然后:

Attempt(() => NativeObject.Property1 = int.Parse(TextObject.Property1));
Attempt(() => NativeObject.Property2 = DateTime.Parse(TextObject.Property2));

1

听起来你想要类似于VB的On Error + Resume Next的功能。 C#没有这样的机制。我能想到的最好的压缩方式是使用Lambda表达式和辅助方法。

private void Wrap(Action del) {
  try {
    del();
  } catch (Exception e) {
    Trace.WriteLineIf(ConverterSwitch.TraceVerbose, e);
  }
}

Wrap(() => { NativeObject.Property1= int.Parse(TextObject.Property1); });
Wrap(() => { NativeObject.Property2= DateTime.Parse(TextObject.Property2); });

0
您可以编写一个 SafeConvert 类来封装转换和日志记录的功能,例如:
public static class SafeConvert{

  public static int ParseInt(string val)
  {
    int retval = default;
    try 
    { 
       retval = int.Parse(val); 
    } 
    catch (Exception e) 
    { 
        Trace.WriteLineIf(ConverterSwitch.TraceVerbose, e); 
    } 
        return retval;
 }

}


0

虽然我不确定异常块缩短的问题,但我喜欢你提出的想法。它类似于旧版VB中的On Error Resume Next。在进行大量解析时,我会使用TryParse(如果可用)的方法。然后你可以这样说:

If(!DateTime.TryParse(TextObject.Property2, out NativeObject.Property2)) {
    // Failed!
}

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