删除过多的try-catch块

时间:2011-08-10 08:06:35

标签: c# winforms exception-handling try-catch

我正在重构由其他开发人员编写的中型WinForms应用程序,并且几乎每个类的每个方法都被try-catch块包围。 99%的时间这些catch只阻止记录异常或清理资源并返回错误状态。

我认为很明显这个应用程序缺少适当的异常处理机制,我打算删除大多数try-catch块。

这样做有什么缺点吗?你会怎么做?我打算:

  • 要正确记录异常并阻止它们传播给用户,请使用Application.ThreadException处理程序

  • 对于需要清理资源的情况,请保留try-catch块

更新:使用usingtry-finally块是更好的方法。感谢您的回复。

  • 在“return-false-on-error”的方法中,让异常传播并在调用者中捕获它

欢迎任何更正/建议。

编辑:在第3项中,“return-false-on-error”我的意思是这样的方法:

bool MethodThatDoesSomething() {
    try {
       DoSomething(); // might throw IOException
    } catch(Exception e) {
       return false;
    }
}

我想把它重写为:

void MethodThatDoesSomething() {
   DoSomething(); // might throw IOException
}

// try-catch in the caller instead of checking MethodThatDoesSomething's return value
try {
   MethodThatDoesSomething()
} catch(IOException e) {
   HandleException(e);
}

7 个答案:

答案 0 :(得分:2)

“要正确记录异常并防止它们传播给用户,请使用Application.ThreadException处理程序”

那么你能告诉用户发生了什么吗?所有例外都会在那里结束吗?

“对于需要清理资源的情况,请保留try-catch块”

如果您希望在其他地方处理异常,也可以使用try-finally块。另请考虑在using资源上使用IDisposable关键字。

“在”return-false-on-error“的方法中,让异常传播并在调用者中捕获它”

这取决于方法。只有在特殊情况下才会出现例外情况。使用FileNotFoundException方法投放FileExists()只是奇怪,但OpenFile()抛出完全合法。

答案 1 :(得分:2)

要进行清理,请使用try-finally或按照Amittai的建议实施IDisposable。对于在出错时返回bool的方法,请尝试并在不满足条件时返回false。实施例。

bool ReturnFalseExample() {
    try {
        if (1 == 2) thow new InvalidArgumentException("1");
    }catch(Exception e) {
       //Log exception  
       return false;
    }

改为改变。

bool ReturnFalseExample() {
    if (1 == 2) {
       //Log 1 != 2
       return false;
    }

如果我没有弄错try catches是一个昂贵的过程,并且在可能的情况下你应该尝试确定是否不满足条件而不是仅仅捕获异常。     }

答案 2 :(得分:1)

您可以尝试使用AOP。

例如,在AOP到PostSharp中,您可以在一个中心位置(一段代码)处理异常作为一个方面。

查看文档中的示例以获得一个想法=> Docs on Exception Handling with PostSharp

答案 3 :(得分:1)

作为“return-false-on-error”的选项,您可以这样清理代码:

    static class ErrorsHelper {
        public static bool ErrorToBool(Action action) {
            try {
                action();
                return true;
            } catch (Exception ex) {
                LogException(ex);

                return false;
            }
        }

        private static void LogException(Exception ex) {
            throw new NotImplementedException();
        }
    }

和用法示例:

    static void Main(string[] args) {
        if (!ErrorToBool(Method)) {
            Console.WriteLine("failed");
        } else if (!ErrorToBool(() => Method2(2))) {
            Console.WriteLine("failed");
        }
    }

    static void Method() {}

    static void Method2(int agr) {}

答案 4 :(得分:1)

你应该只处理你期望的异常,知道如何处理它们并且它们不会破坏你的应用程序的状态,否则就让它们抛出。

一个好的方法是首先记录异常,然后重新启动您的应用程序,就像Microsoft在办公室或Visual Studio崩溃时所做的那样。为此,您必须处理应用程序域无法处理的异常,因此:

AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;

//Add these two lines if you are using winforms
Application.ThreadException += OnApplicationThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

private void OnCurrentDomainUnhandledException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
    //Log error

    //RestartTheApplication
}

Here有关如何重新启动应用程序的示例。

答案 5 :(得分:1)

我认为你删除try / catch块的策略似乎只是做了通用的无思路日志记录。显然需要保留清理代码。但是,我认为第三点需要进一步澄清。

对于异常不可避免的事情,错误方法返回false通常是正常的,例如示例中的文件操作。虽然我可以看到删除异常处理代码的好处,但是我会仔细考虑通过在调用链中推动处理此类异常的责任而获得的好处。

如果方法正在做一些非常具体的事情(它不是通用的框架代码),并且你知道哪些调用者正在使用它,那么我会让它吞下异常,让调用者免于异常处理任务。但是,如果它是更通用的东西,也许更多的是框架方法,你不确定将调用该方法的代码,我可能会让异常传播。

答案 6 :(得分:0)

最好的是其他人说的,在1个地方做异常处理。不好的做法是隐瞒引发的异常,而不是让它冒出来。