【问题标题】:Main method code entirely inside try/catch: Is it bad practice?主要方法代码完全在 try/catch 中:这是不好的做法吗?
【发布时间】:2011-06-17 04:35:11
【问题描述】:

通常我将我所有的 Main 方法代码放在一个 try/catch 块中,如下所示:

public static void Main(string[] args)
{
   try
   {
      // code
   }
   catch (Exception e)
   {
      // code
   }
}

我这样做是为了以防任何异常从程序逻辑的其余部分中溜走,从而允许我对其进行一些处理,例如将其显示到控制台、将其记录到文件等。但是,我被告知这是不好的做法。

你认为这是不好的做法吗?

【问题讨论】:

标签: c# oop programming-languages exception-handling try-catch


【解决方案1】:

在没有充分理由的情况下将任何段代码包装在 try/catch 块中是不好的做法。

在 .NET 编程模型中,应为真正的异常情况或条件保留异常。您应该尝试捕获您实际上可以做某事的异常。此外,您不应该永远捕获基本的System.Exception 类(而是更愿意捕获您可以处理的更具体的派生异常类)。如果在您的程序执行过程中遇到真正意外的异常,您实际上应该崩溃。

显然,“正确”的答案必须根据具体情况做出,具体取决于 catch 块中的 // code 占位符内部发生的情况。但是,如果您要求一般规则或“最佳实践”,您应该始终有特定的理由来捕获异常,而不是理所当然地将所有代码包装在一个巨大的 try/catch 块中不假思索。

请注意,如果您只是为了记录或错误报告的目的而尝试捕获任何可能发生的未处理异常,您应该使用AppDomain.UnhandledException event。这是一个仅通知事件,因此它不允许您处理这些异常,但它是在应用程序崩溃后实现日志记录或错误报告功能的正确位置。


编辑:当我在阅读 Raymond Chen 的优秀博客 "The Old New Thing" 时,我注意到他最近发表了一篇关于类似主题的文章。它特定于 COM,而不是 .NET Framework,但有关错误处理的一般概念同样适用于这两种环境。我想我会在这里分享这篇文章中的一些精华,以支持我的[显然颇有争议]的观点。

从历史上看,COM 在服务器的方法周围放置了一个巨大的 try/except。如果您的服务器遇到通常未处理的异常,巨大的 try/except 会捕获它并将其转换为错误 RPC_E_SERVERFAULT。然后它将异常标记为已处理,以便服务器保持运行,从而“即使遇到问题也能保持服务器运行,从而提高稳健性。”

请注意,这实际上是一种伤害。

发生未处理的异常意味着服务器处于意外状态。通过捕获异常并说“别担心,一切都很好”,您最终会让损坏的服务器继续运行。

[ . . . ]

捕获所有异常并让进程继续运行假定服务器可以从意外故障中恢复。但这是荒谬的。您已经知道服务器无法恢复:它崩溃了!

更好的是让服务器崩溃,以便可以在故障点捕获崩溃转储。现在你有机会弄清楚发生了什么。

您可以[并且应该]在他的博客上阅读整篇文章:How to turn off the exception handler that COM "helpfully" wraps around your server

【讨论】:

  • @gridzbi:好吗?在AppDomain.UnhandledException 事件中这样做。这就是它设计的目的。将代码包装在 try/catch 块中通常是一个的想法,尤其是对于这样的事情。一个真正未处理的异常,您无能为力应该导致您的应用程序崩溃。日志记录是次要问题,并且已经为此做出了规定。
  • 永远不要说“从不”。在很多情况下,您必须捕获 System.Exception。例如,如果你正在处理一个任意插件调用,它可能会抛出任何东西,但如果有任何失败,你应该优雅地杀死它。或者,如果您正在解释用户输入的任意代码,这可能会抛出任何东西 - 在这种情况下,您必须向用户显示堆栈跟踪并返回到 repl。
  • @SK-logic:我不熟悉用户可以提出自己的异常的情况。是的,我想可能会有第 3 方库出错并提出 System.Exception,但这仍然不是用 try/catch 块吞下 所有 代码的借口。请注意,我的其余答案对于必须根据具体情况做出决定是非常宽容的;我认为原始问题的方式是“最佳实践”之一,而不是“这是否合理?”
  • @Cody Gray,如果它是一个插件,而不是一个库,即使插件严重失败,您的应用程序也可以继续运行 - 只需关闭此插件并抱怨。失败的细节并不重要。如果有嵌入式脚本语言,用户可以抛出异常,情况也是如此——这是一个非常典型的场景。我在回答您的声明,即对于任何代码都不是一个好习惯,但我当然同意 Main()。
  • @Apalala:是的。当您调试应用程序时,这是一个绝妙的主意。但不是在您部署应用程序时。这就是问题所在:无论哪种方式,你都会在用户面前崩溃。将Main 方法包装在try/catch 块中并按照您的建议重新抛出 错误根本没有任何意义。错误已经抛出!它已经达到了最高水平。你通过重新抛出它来完成nothing。我已经解释了你如何记录错误。为此内置了一种方法;没有理由尝试/捕捉。
【解决方案2】:

我同意科迪所说的 90%。在某些类似于插件示例的情况下,您可能希望捕获系统异常。这是另一个考虑使用 WCF Web 服务的示例。

目标:即使遇到错误,也要使用服务并丢弃。让错误冒泡。

public static bool DoRemoteWebServiceWork()
{
    bool result;
    RemoteWebServiceClient client = new RemoteWebServiceClient();
    try
    {
        result = client.DoWork();
        client.Close();
    }
    catch (Exception)
    {
        client.Abort(); //dispose
        throw;//This service is critical to application function. The application should break if an exception is thrown.
        //could log end point and binding exceptions to avoid ignoring changes to the remote service that require updates to our code.
    }
    return result;
}

目标:即使遇到错误,也要使用服务并丢弃。防止错误冒泡。

public static bool DoRemoteWebServiceWork()
{
    bool result;
    RemoteWebServiceClient client = new RemoteWebServiceClient();
    try
    {
        result = client.DoWork();
        client.Close();
    }
    catch (Exception)
    {
        client.Abort(); //dispose
        //throw; //This service is auxiliary to the applications primary function. We have no influence over the service and therefore cannot fix it.
        //could log end point and binding exceptions to avoid ignoring changes to the remote service that require updates to our code.
    }
    return result;
}

【讨论】:

    【解决方案3】:

    当然,是的,使用异常类是一种不好的做法

    您应该关心异常的类型,而不是在 catch 块上删除所有异常,防止它们通知系统错误。

    异常类是一个基类,并且,是一个可以在代码中捕获的顶级异常。在 catch 块中使用最具体的异常,特别是在 try {...} catch{...} 块中编写的唯一异常,并且仅当它可以在该特定级别上有效解决(在函数,其中声明了 try..catch 块)

    【讨论】:

      【解决方案4】:

      如果您正在尽最大努力解决错误,那么这是一种很好的做法。这就是 try/catch 的用途。

      如果您只是扔掉错误(或记录并扔掉它)——尤其是不管异常类型如何都这样做——这被认为是不好的做法。

      这可能会引发一个问题:如果最明智的做法是将其记录下来然后扔掉呢?我想说这将是一个例外情况。但在实践中,我的代码会以其他方式断言。我想我沉迷于很多不好的做法。

      【讨论】:

      • 我同意,但你仍然不应该抓住System.Exception。你会捕捉到一个更具体的、派生的异常,你可以对它做点什么。
      【解决方案5】:

      这取决于你在发现错误时会做什么。如果您只是捕获 all 错误以优雅地处理它们 - 不好的做法。我会说即使您只在那里登录也是不好的做法 - 在本地登录。

      如果你真的做了一些事情来恢复错误(例如,你自己扔了它并且知道该怎么做)-我会投 OK :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-27
        • 2016-04-13
        • 2010-10-01
        • 2011-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多