使用try / catch / finally执行常规类?

时间:2010-06-11 08:16:34

标签: c# exception-handling aop

我发现自己在我的代码中有很多不同的方法:

try
{
  runABunchOfMethods();
}
catch (Exception ex)
{
  logger.Log(ex);
}

如何创造这个:

public static class Executor
{

    private static ILogger logger;

    public delegate void ExecuteThis();

    static Executor()
    {
        // logger = ...GetLoggerFromIoC();
    }

    public static void Execute<T>(ExecuteThis executeThis)
        where T : Exception
    {
        try
        {
            executeThis();
        }
        catch (T ex)
        {
            // Some kind of Exception Handling Strategy...
            logger.Log(ex);
            // throw;
        }
    }

}

就这样使用它:

private void RunSomething()
{
  Method1(someClassVar);
  Method2(someOtherClassVar);
}

...

Executor.Execute<ApplicationException>(RunSomething);

这种方法有什么缺点吗? (您可以在需要finally时添加Executor方法和委托,并使用泛型来处理要捕获的Exeception类型...)

编辑:很抱歉不清楚 - 我真正想到的是关于尝试将代码的执行从有问题的类移动到更广泛的类的一般想法的一些输入。我只是快速模拟了一个解决方案,但在现实生活中,您自然会使用诸如异常处理策略,抽象执行基类以及针对特定层/系统部分的更专业的执行类。我通常使用try ... / runABunchOfMethods-part创建一个方法(这会执行异常处理,具有特殊的异常),调用runABunchOfMethods,然后执行一组有限的其他方法“clean code”样式。

我会在某些层面上购买混淆论点,但如果整个解决方案/架构采用这种方法,新程序员应该能够理解这种模式。

我编辑了Executor以包含一个通用T,允许调用代码指定exeception以显示如何处理专门的异常。在其他情况下,你可能会有一堆问题:es取决于你想要做什么,但这些是我所讨论的具体子类中的特殊情况。

9 个答案:

答案 0 :(得分:12)

缩减是一般异常处理的方法。没有充分理由,你不应该抓住基类Exception。它可以隐藏各种问题;好吧,你记录它们,但你的代码不知道它只是运行内存不足,或文件不存在并继续,好像没有问题所有。
您在此处描述的方法将鼓励一般的异常处理。

相关:
Is it really that bad to catch a general exception?
Is this a bad practice to catch a non-specific exception such as System.Exception? Why?

编辑(对OP的编辑和澄清的回应):
我不确定你想要达到什么目的。 Basicall你隐藏一个异常(一般或指定 - 它只是被吞下)。调用您的方法Executor.Hide<ApplicationException>( RunSomething );,很清楚这里发生了什么。但吞咽异常有什么好处吗?我不这么认为。同样,有些地方你需要这个 - 但它们很少见,应该有意选择。您提供的方法鼓励在不考虑的情况下吞下异常 您注释掉了重新抛出线(throw ex或更好的throw,它保留了堆栈)。你启用这条线怎么办?基本上只是记录。你捕获一个异常,记录它并重新抛出它...再次捕获它?你为什么不把你的伐木记录到后一个地方呢? 当你能够处理它时,尝试仅捕获异常。那里你也可以登录。任何好的记录器都能显示堆栈跟踪,这样就不会丢失任何信息。

相关:
Where to put try catch?

答案 1 :(得分:3)

你得到另一层间接性,这可能会使你的代码更难以阅读和理解(特别是对于第一次看你的代码的人)。

答案 2 :(得分:2)

你没有赢得任何东西,但是你失去了一些东西:

  • 可读性
  • 简单(你介绍另一个类,读者必须理解的另一个代表)
  • 你不能简单地跨过Executor.Execute来获取Method1(...)。如果您跳过,则跳过代理中的整个代码块。
  • ...

答案 3 :(得分:2)

如果要保持对象清洁,可以考虑使用像PostSharp这样的AOP框架。然后,如果您愿意,可以在一个地方处理例外记录(例如)。

编辑:

可以使用postsharp删除try / catch块 - 这是一个可以在PostSharp中创建的常见异常处理程序示例:

[Serializable]
public class CommonExceptionHandling : OnExceptionAspect
{
    public override void OnException(MethodExecutionEventArgs eventArgs)
    {
        // can do some logging here
        // ...

        // throw the exception (out of postsharp) to where it occurred:
        eventArgs.FlowBehavior = FlowBehavior.RethrowException;                       

        // If you want to ignore the exception, you can do this:
        //eventArgs.FlowBehavior = FlowBehavior.Return;

        base.OnException(eventArgs);
    }
}

如果将此属性应用于类,则该类中任何方法抛出的任何异常都将通过上述代码进行定向。

答案 4 :(得分:1)

缺点是缺乏灵活性。如果你想从被调用的方法中的特定异常中恢复,例如,如果与SMTP服务器连接失败,您可能希望将出站邮件的内容存储在数据库中以便稍后重试?这就是为什么你应该尽可能避免捕获一般的Exception类型。

此外,你失去了一些代码的清晰度(在我看来,无论如何),因为很难看到异常处理发生的地方。

答案 5 :(得分:1)

如果你在很多课程中看到那些代码,那么你在我的书中做了一些非常错误的事情:-)在至少你应该重新抛出异常(只有“throw”,而不是“throw(ex)”),但是记录基本异常的整个想法只是为了记录它(或者确实在任何时间,禁止一些边缘情况)是对我来说不是正确的方法。

我不知道你正在编写什么样的应用程序,但是你不能挂钩AppDomain.UnhandledException之类的事件,只要在任何线程中出现未处理的异常(你没有捕获的异常),它就会触发,并记录那些?如果您还要记录可恢复的异常,您可能希望将其与更具体的catch语句(也记录日志)结合使用。

答案 6 :(得分:1)

我会跳到“它会让你有可能滥用例外,只能抓住一般水平”的潮流。但是,在更专业的情况下,您可能会从某种“异常处理委托包装器”中受益。例如,如果你在与DB相关的类中做了很多工作,这些类总是抛出相同的异常,那么你可以拥有一个专用的DB异常包装器。

最终,例外情况“混乱”你的代码是使你的代码安全的缺点。

答案 7 :(得分:1)

通常,在应用程序中记录异常的最佳模式是捕获代码中顶级方法的异常。

  • 在控制台应用程序中,您应该捕获并记录Main中的异常。
  • 在WinForms应用程序中,您应该捕获并记录事件处理程序中的异常。
  • 在服务中,您应该捕获并记录异常,然后记录工作线程的ThreadProcs

在应用程序的几乎所有其他位置,您应该只捕获特定的异常,然后重新抛出包装原始异常的新异常。如果您不需要包装原始异常,则首先不需要捕获原始异常。

如此设置您的应用程序只会导致您捕获,记录和“吞下”异常的几个地方。

答案 8 :(得分:0)

刚开始......

你的代码库中不应该有像下面这样的代码。

try 
{ 
  runABunchOfMethods(); 
} 
catch (Exception ex) 
{ 
  logger.Log(ex); 
} 

我建议你首先看一下像这样的代码的实际需要。您应该在所有情况下捕获一个非常特殊的异常(与通用的catch全部不同)。

之后,如果您仍然有多个方法捕获相同的异常,那么您可以考虑在执行程序中创建多个方法来处理特定的异常类型。