关于c#:try catch语句的位置


position of the try catch statement

我有一些代码目前看起来有点像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void MainFunction()
{
   try
   {
      SomeProblemFunction();
   }
   catch
   {
      AllFineFunction();
   }
}

private void SomeProblemFunction() { ... }
private void AllFineFunction() { ... }

如您所见,我目前正在将对SomeProblemFunction的调用包装在try语句周围,因为该函数可能会失败(它依赖于外部Web服务调用)。

我的问题是:try语句应该是a)在问题函数之外(就像我现在拥有的那样)还是b)在问题函数之内?

谢谢。


通常,您希望允许异常传播到应用程序边界。除此之外,你只想做几件事中的一件:

  • 包装它
  • 替换它
  • 让它传播

更新

从您的问题来看,您似乎正在为您的Web服务调用寻找一个容错解决方案。这是一个比简单的"我要把我的试捕获放在哪里"更复杂的问题。您仍然将异常处理放在应用程序边界上,但在那里您将实现您的容错策略。这需要考虑很多因素,包括异步调用Web服务、重试次数等。我建议您搜索Web服务容错性。


您所拥有的是正确的;请参阅msdn示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class ThrowTestB
{
    static void Main()
    {
        try
        {
            // TryCast produces an unhandled exception.
            TryCast();
        }
        catch (Exception ex)
        {
            // Catch the exception that is unhandled in TryCast.
            Console.WriteLine
                ("Catching the {0} exception triggers the finally block.",
                ex.GetType());

            // Restore the original unhandled exception. You might not
            // know what exception to expect, or how to handle it, so pass  
            // it on.
            throw;
        }
    }

    public static void TryCast()
    {
        int i = 123;
        string s ="Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // Report that the finally block is run, and show that the value of
            // i has not been changed.
            Console.WriteLine("
In the finally block in TryCast, i = {0}.
"
, i);
        }
    }
    // Output:
    // In the finally block in TryCast, i = 123.

    // Catching the System.InvalidCastException exception triggers the finally block.

    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
}


根据经验法则,我尝试构建将try捕获集中到确切位置的代码,这可能会发生问题。

也就是说你的两个解决方案都是正确的。

如果是我的代码,我会这样做的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void MainFunction()
{
   try
   {
      SomeProblemFunction();
   }
   catch(Exception e)
   {
      Messagebox.Show(e.Message);
   }
}

private void SomeProblemFunction() {
    try{
        web call
    }
    catch{
         throw a specific exception related to this spot
    }
}
private void AllFineFunction() { ... }

使用此方法,您可以轻松创建处理大量非常精确异常的应用程序。


我想这是个很好的问题。我试着回答。

如果您希望在SomeProblemFunction内恢复,那么将try...catch移动到该方法内是完全合理的。但是,如果你认为如果SomeProblemFunction中有任何失败,那么整个事情就是失败,那么就保持现状,恢复(或放弃)MainFunction中的状态。

感谢下面的评论,我将增加一些清晰度。根据在SomeProblemFunction中抛出的特定异常,您可能无法在该方法中恢复。如果你有一个可回收和不可回收的混合物,那么在两个地方都有try...catch是明智的。

最重要的是,你永远不会抓住一个例外,从中你无法恢复,不把它扔在你的事情之后。为了避免你的应用程序在开发过程中崩溃,增加大范围捕获(catch (Exception))是很有诱惑力的,但它永远都不值得。如果这些东西进入了您的生产代码中,那么您就引入了一个解决问题和调试的噩梦。


这取决于此Web服务调用失败的严重程度。

它是否会阻止代码的进一步处理运行?如果是这样,这里就不要尝试/捕获,允许它传播给需要知道这个Web服务调用失败的人。或者,您仍然可以捕获并抛出一个新的异常,其中包含一些更有意义的异常类型/详细信息。

如果Web服务调用不起作用,您只是想重新尝试一下吗?如果是这样,那么您可以在正确的位置进行尝试;您只需要添加一个循环。

如果这个Web服务调用失败,这不是什么大问题吗?你的代码其余部分工作正常吗?(我发现这很少见)。如果是,请将Try/Catch保留在它所在的位置,并将错误记录在某个位置,以便您收到警报。


在我看来,这个问题没有直接的答案。try catch用于处理可能发生的异常。如果您的异常处理代码在主函数中,那么您应该在主函数中有try catch。如果您的异常处理代码在问题函数中,那么您应该将它添加到问题函数中。

不过,我倾向于把它放在两个函数中。如果将try catch放入problem函数中,可以抛出异常并在主函数中捕获它。对于其他开发人员来说,这个异常总是在这个函数中被想到的,并且不会因为错误而错过处理它。