繁体   English   中英

当用户输入凭据时,如何出现由凭据弹出窗口引起的异常,如何继续执行catch块?

[英]How can I continue execution of a catch block when the user enters credentials, from an exception caused by a credentials popup appears?

我制作了一个Winforms应用程序,该应用程序访问另一个服务器(在另一个活动目录域中)上的文件夹。 从文件夹中获取所有目录的行,但有时可能会失败,因为未保存访问文件夹的凭据(基本身份验证),因此基本身份验证对话框一次又一次弹出,从而破坏了系统。

在相应的catch块中,在用户输入其凭据然后重试相应的代码之后,如何通过恢复catch块的执行来处理该问题?

谢谢

通常最好让异常传播到UI,然后将问题报告给用户。 然后,用户可以决定重试该操作。 当然,这假定可以还原系统的状态。 如果可以以可以恢复系统状态的方式对操作进行编码,那将是最好的,因为这样,在存在其他异常的情况下,该操作也会很健壮。

如果重试必须从异常的角度继续进行,那么最好的选择可能是将该步骤放在一个循环中,如下所示:

private const int maxRetryAttempts = 3;

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while (true)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             if (remainingAttemtps <= 0)
                 throw;
             remainingAttempts--;             
             MessageBox.Show(ex.Message);
        }
    }
}

一会儿的原因(正确)

while(true){...}语句可能看起来有些奇怪,但是在这种情况下是必须的。 它不是一个无限循环,因为该方法将在指定的迭代次数内返回值或引发异常。

通常,您会期望一个带有非恒定控制表达式的循环。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)  //  Non-constant expression.
    {
        ...
    }
}  //  Compile error - Not all code paths return a value.

为了满足编译器的可达性检测器,未在此方法中执行此操作。 编译器将在while语句中看到常量true,并且知道while之后的语句不可访问,因此,方法的末尾不可访问。 如果选择了非常量,则必须在循环后放置代码以返回值或引发异常。 让我们考虑每个选项。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    return null;
}  

我们可以返回一个空值(或其他错误指示​​符),在这种情况下,调用代码将必须期望空值并对其进行处理。 在我看来,这似乎是一个笨拙的设计。 我宁愿保证,如果该方法返回,那么它将返回一个好的值。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    throw new UnauthroizedAccessException();  // This exception does not contain any good debugging data.
}  

另一种选择是在方法末尾引发异常。 这是一个合理的选择,但不是理想的选择。 如果我们创建一个新的异常,那么它几乎肯定比起最初导致问题的问题(已经被捕获并丢弃)的意义要小。

假设我们保存原始异常。

private static MyData ReadDataFile(string path)
{
    UnauthorizedAccessException exception = null;
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             exception = ex;
             MessageBox.Show(ex.Message);
        }
    }
    throw exception;  // The StackTrace gets replaced to indicate this line of code.
}

我们可以通过在方法顶部创建一个Exception变量并将捕获的异常存储在其中来重新抛出捕获的异常。 这样做的问题是它将导致堆栈跟踪被替换,并且将来使调试该应用程序变得更加困难。 最好通过使用throw;来让异常保持不变throw; 重新抛出原始异常(只能在catch块中发生,而不能在方法末尾发生)。

因此,在所有可用的替代方法中,我认为while(true)是最佳选择,因为它可以确保控件将为该方法保留良好的数据或未损坏的异常。

请注意,如果该方法没有返回值( void ),那么可达性问题就消失了,但逻辑上就没有了。 我们仍然必须处理方法退出的问题,而不必执行应做的事情。

private static void ReadDataFile(string path)
{
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             MessageBox.Show(ex.Message);
        }
    }
    //  Compiles justs fine, but did we actually read the data file? 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM