异常处理类
什么是异常处理,而不必把try/catch块随处可见的最佳做法?异常处理类
我必须创造出一种专门用于接收和处理异常一类的想法,但如果我想知道一个良好的设计理念。这样的类将收到异常,然后再决定如何处理它根据其类型或错误代码做,甚至可以解析为特定的堆栈跟踪信息,等
这里是背后的基本思想和实现:
public class ExceptionHandler
{
public static void Handle(Exception e)
{
if (e.GetBaseException().GetType() == typeof(ArgumentException))
{
Console.WriteLine("You caught an ArgumentException.");
}
else
{
Console.WriteLine("You did not catch an exception.");
throw e; // re-throwing is the default behavior
}
}
}
public static class ExceptionThrower
{
public static void TriggerException(bool isTrigger)
{
if (isTrigger)
throw new ArgumentException("You threw an exception.");
else
Console.WriteLine("You did not throw an exception.");
}
}
class Program
{
static void Main(string[] args)
{
try
{
ExceptionThrower.TriggerException(true);
}
catch(Exception e)
{
ExceptionHandler.Handle(e);
}
Console.ReadLine();
}
}
我认为这将是一个有趣的尝试,因为理论上你只需要在main()方法调用周围需要一个或很少的try/catch块,并让异常类处理其他所有事情,包括重新抛出,处理,记录,不管。
的思考?
其实是有一个很好的理由,为什么你不看到在生产代码类似的设计。
首先,这样的设计不能帮助您减少代码中try
/catch
对的数量(这应该是显而易见的)。它可以帮你减少catch
报表给定try
数量,因为你可能只是赶上System.Exception
并转发到ExceptionHandler
......
但接下来呢?
每一种异常需要进行不同的处理。 ExceptionHandler
怎么会知道该怎么做?你可以尝试多种方式,例如,以解决这个问题:
- 从
ExceptionHandler
派生,并把代码中的虚拟方法来处理异常 - 通过一些
Action<Exception>
实例的处理程序,并让它调用现在你需要创建一个全新的类各try
块,并覆盖了一堆的方法的东西糟糕比你结束了:以前正确的一个
解决方案(1)会比你有什么更糟糕之前(不是我)立即清楚特定类中的代码如何适合程序的流程)。这也会让另一个重要问题得不到解决:您可能需要上下文(访问当前范围中的变量)来正确处理异常。你将如何提供访问这个上下文?解决方案(2)实际上最终会非常类似于编写我们想要避免的catch
块(每个Action
实际上将是catch
块的内容)。我们最终只会以更复杂和冗长的方式做同样的事情。
也有其他的问题:
- 我应该做
ExceptionHandler
如果它不能处理异常?再次投掷会导致您丢失原始堆栈跟踪,实际上会破坏其中的所有良好信息。 - 如果在
ExceptionHandler
有错误怎么办?你可以使用try
/catch
。你能相信你自己编写的代码到相同的程度吗?
至于ExceptionThrower
...它可能提供什么好处,而不是throw new Exception();
?
异常处理已经非常复杂,并且很难在不添加额外齿轮的情况下正确处理。特别是如果他们不给你买任何新东西的话。 不要这样做。
以一个简单的控制台应用程序为例 - 如果我在执行UI的Main()方法中有一行代码,并且试图捕获它,那么不会在应用程序中发生任何异常,直到该catch块?或者我错过了什么?为什么我需要超过单一的try/catch? – 2011-04-06 22:54:51
@SeanThoman:因为有些例外可以合理预期(例如试图打开一个文件,你可能会得到一个'FileNotFoundException')以及意味着游戏结束的异常(例如'ExecutionEngineException')。你无法从同一个地方合理地回应;你需要不同的上下文。 – Jon 2011-04-06 22:59:06
我认为你可以通过配置处理类的逻辑,但它可能太复杂,并引入自己的错误,如你所说。如果这是一个非基于UI的应用程序,那该怎么办呢?只是一个工作应用程序按顺序执行一些进程,完全放手,管理员只需定期检查日志以确保事情顺利进行。你不希望应用程序停止运行某些例外,等等。 – 2011-04-06 23:07:56
OK,这可能不是你想要我通常对一般的异常处理类的想法过敏的答案,但...
。你几乎可以听到它本身就是一个矛盾。例外情况是例外事件。异常事件不能在一般的方式来处理,但需求量身定制的操控无论他们在哪里出现,这基本上意味着你的代码应该有两点:
- 是防守有关,以避免在例外的任何输入首先
- 把
try..catch
块无论是有意义捕捉和处理异常(注意,这意味着,你不应该在所有的方法try..catch
块)
那么,捕捉和处理异常的意义何在?简而言之,您的代码具有能够处理异常的知识。如果没有,请让异常向上调用。 只有我认为你应该捕获所有异常,并在你的应用程序的顶层有一些通用的默认行为。这通常是UI。
对不起,这不是一个好主意。当你在你的代码中用正常的try/catch块在相关部分周围捕获到一个异常时,你可以使用两个关键信息来处理这个问题:异常的类型,还有发生异常。
根据您的安排,您必须处理所有异常,只知道它们是哪种类型的异常。您不再知道异常实际发生的位置,因此除了记录日志或向用户显示消息之外,您无法对此问题进行任何操作。此外,try/catch块通常还包含一个finally块,在这个块中,即使抛出异常(如关闭流等),也可以确保事情发生。你在处理这件事的安排上没有任何办法。
适当的异常处理可能会非常棘手,并且没有任何灵丹妙药可以使它变得简单明了。如果有的话,.Net将已经合并它。
您可以通过使用堆栈跟踪来了解它发生的位置......但我确实看到了您的观点。由于使用'throw e'会破坏堆栈跟踪,而只使用'throw'只能在catch块中使用,所以似乎很棘手..您必须记录堆栈跟踪或编程地在堆栈跟踪之前执行某些操作E”。 – 2011-04-06 23:00:48
你的意思是如果你写了一个堆栈跟踪解析器(yay!),你可以推断出现异常的地方。没错,但是你仍然需要在某处放置代码,以便对特定的异常类型和位置信息做出适当的响应。为什么不把它放在正常的catch块中,就在导致问题的代码的下面? – MusiGenesis 2011-04-06 23:05:04
我们在我们的代码库中有一个类,它与您提议的代码具有非常相似的签名,现在我可以告诉您它只有痛苦和痛苦!
为什么你的代码中有这么多的try-catch块?你能举一些例子吗?异常的性质“非常”,即不那么频繁!你不仅应该经常捕捉异常,而且每个异常都是不同的,并且在一种情况下工作的相同样板代码可能不适用于许多其他情况。没有人说异常处理很容易(或者生成紧凑的代码) - 你应该认为仔细关于你需要捕捉异常并适当处理它的每种情况 - 避免捕捉你不需要处理的异常。
我实际上没有那么多尝试抓块......但我很好奇这个想法。 – 2011-04-06 23:05:21
通过在你的'ExceptionHandler'类中重新抛出异常,你将失去先前的堆栈跟踪。 – 2011-04-06 22:45:56
有没有办法保存堆栈跟踪? – 2011-04-06 22:52:18
用'throw;'替换'throw e;'' – 2011-04-06 22:53:03