簡體   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