修改现有程序以更好地处理异常

时间:2012-09-20 16:41:43

标签: c# exception try-catch

我正在开发一个现有的C#程序,该程序可以查询并更改运行该程序的程序和计算机之外的各种资源。该程序适用于大多数计算机,但在随机计算机上经常随机失败。当发生这种情况时,我们没有反馈为什么除了用户告诉我们关于屏幕上抛出的异常之外的原因,他们可能已经或可能没有清除过。即使他们把它留在屏幕上给我们,它也几乎没有给我们提供有用的信息。我已经修改了程序以记录特定事件并将信息收集到一个文本文件中,我可以用它来估算程序停止的位置。这至少是一个开始,但是从阅读stackoverflow.com以及其他论坛上的许多线程我知道该程序至少需要尝试处理查询和修改LDAP,DS,DNS时可能出现的特定异常,SQL等。

目前只有很大的尝试块围绕着所有的代码,每个代码只有一个catch块。

private void method_name()
{
    try
    {
       //many lines of to do code calling many other methods
    }
    catch (exception ex)
    {
        MessageBox.Show("An Error has occurred in method_name() :" + ex.Message);
    }

我的第一个想法是在更大的try块中嵌套更具体的try / catch块但是我一直遇到变量在不同的上下文中无法访问的问题。例如

try
{
   LdapConnection ldapConn = new LdapConnection();
   ldapConn.Connect(details of connection);
   ldapConn.Bind(details of bind statement);
   LdapSearchQueue queue = ldapConn.Search(search criteria and such);
   LdapMessage message;
}
catch (somesortofexception ex)
{
   //do something sensible about it
}

while ((message = queue.getResponse()) != null)
{
   //do things with message
}
ldapConn.Disconnect();

问题是在try块之外无法访问消息和队列。这只是我尝试使用的“//多行代码调用许多其他方法”所做的事情的一个例子。

所以这是我的问题:

在上面的例子中尝试使try块更大,以包括while循环和ldap disconnect或者只是离开大的try循环,列出在此期间发生的事情并创建许多catch块会更好吗?最后要抓住具体的例外情况?我觉得在特定代码周围放置较小的试块是基于我在本网站上阅读的内容。

我是否应该使用像我一直尝试实现的较小的try块,可以使用catch块来捕获在该小代码片段中引发的任何异常并将其记录到我的日志文件中,或者我应该尝试捕捉特定的例外情况?除了将它们记录到文件之外,我对这些异常没有任何不同之处。

我是否需要抛出异常?除了简单的英语消息说出现问题并联系IT之外,我真的不希望任何东西冒充用户。目前没有一个捕获块扔掉任何东西。

2 个答案:

答案 0 :(得分:0)

只要您期望该异常并且可以在本地处理,那么吞下特定异常的本地catch块就可以了。在这种情况下,您可以仅根据异常包含的内容向用户提供信息,或者如果要将其状态包含在日志记录和/或消息中,则可以将变量定义移到try块上方。

对于您不期望的异常,您应该让它们向上冒泡到调用堆栈的顶部,然后可以通过全局处理程序记录它们,然后再正常退出程序。你不希望通过吞下这些例外来将尸体钉在直立的位置。

假设这是一个WinForms应用程序,全局处理程序的设置如下所示:

public static void Main(string[] args)
{
    // Switch-off the Windows Forms default handler for unhandled exceptions.
    // NB From .NET 4 upwards, this won't work if the process state is corrupted.
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

    // Setup event handler to intercept an unhandled exception on a UI thread.
    // NB The exception will still terminate the application. 
    // But you can show a MessageBox and/or log the exception. 
    Application.ThreadException += 
        new ThreadExceptionEventHandler(App_UiThreadException);

    // Setup event handler to intercept unhandled exception on a non-UI thread.
    AppDomain.CurrentDomain.UnhandledException += new 
        UnhandledExceptionEventHandler(App_NonUiThreadException);

    // Run the application (open main form etc).    
}

答案 1 :(得分:0)

关于分解异常,我总是将连接代码与查询分开。

所以这会变成:

LdapConnection ldapConn = new LdapConnection();
try
{
   ldapConn.Connect(details of connection);
   ldapConn.Bind(details of bind statement);
}
catch (somesortofexception ex)
{
   //Log, send error message..
   ldapConn = null;
}

if (ldapConn != null)
{
    try
    {
         //Do what you need with your connection
    }
    catch (Exception ex)
    {
         //Log, Error....
    }
    finally
    {
        //Disconnect your ldap here
    }
}

理想情况下,我会将所有连接代码和搜索代码放在不同的方法中, 所以你会有更好的堆栈跟踪。

关于错误消息我也会使用一些通用消息并将异常细节记录到某种文件(http://logging.apache.org/log4net/)中,这对于格式化日志文件来说非常好。