簡體   English   中英

如何構造一個try-catch-finally塊以最終處理內部錯誤?

[英]How can I structure a try-catch-finally block to handle errors inside finally?

我在調用第三方C ++ dll時遇到問題,我使用DllImport將其包裝在一個類中以訪問其功能。

dll要求在使用前打開一個會話,該會話將返回一個整數句柄,用於在執行操作時引用該會話。 完成后,必須使用相同的句柄關閉會話。 所以我做了這樣的事情:

public void DoWork(string input)
{
    int apiHandle = DllWrapper.StartSession();

    try
    {
        // do work using the apiHandle
    }
    catch(ApplicationException ex)
    {
        // log the error
    }
    finally
    {
        DllWrapper.CloseSession(apiHandle);
    }
}

我的問題是,CloseSession()有時會導致有問題的Dll在運行線程時拋出錯誤:

System.AggregateException:發生一個或多個錯誤。 ---> System.AccessViolationException:嘗試讀取或寫入受保護的內存。 這通常表明其他內存已損壞。

我不確定要停止此錯誤有很多辦法,因為它似乎是由於以線程方式使用Dll引起的-它應該是線程安全的。 但是,由於我的CloseSession()函數除了調用Dll的close函數外什么也不做,因此我沒有太大的空間來“修復”任何東西。

但是,最終結果是會話無法正確關閉。 因此,當該過程再次嘗試執行時(應執行的操作),它將遇到一個打開的會話,並不斷拋出新的錯誤。 那屆絕對必須關閉。

我對如何設計一個更健壯的錯誤處理語句感到困惑,該語句將確保會話始終關閉?

我將更改包裝器,以包括處理外部資源並包裝手柄。 即,不是用句柄表示會話,而是用包裝對象表示會話。

此外,將對DLL的調用包裝在lock語句中(如@Serge所建議的那樣),可以完全防止多線程問題。 請注意,鎖定對象是靜態的,因此所有DllWrappers都使用相同的鎖定對象。

public class DllWrapper : IDisposable
{
     private static object _lockObject = new object();

     private int _apiHandle;
     private bool _isOpen;

     public void StartSession()
     {
         lock (_lockObject) {
             _apiHandle = ...; // TODO: open the session
         }
         _isOpen = true;
     }

     public void CloseSession()
     {
         const int MaxTries = 10;

         for (int i = 0; _isOpen && i < MaxTries; i++) {
             try {
                 lock (_lockObject) {
                     // TODO: close the session
                 }
                 _isOpen = false;
             } catch {
             }
         }
     }

     public void Dispose()
     {
         CloseSession();
     }
}

請注意,這些方法現在是實例方法。

現在,您可以使用using語句確保關閉會話:

using (var session = new DllWrapper()) {
    try {
        session.StartSession();
        // TODO: work with the session
    } catch(ApplicationException ex) {
        // TODO: log the error
        // This is for exceptions not related to closing the session. If such exceptions
        // cannot occur, you can drop the try-catch completely.
    }       
} // Closes the session automatically by calling `Dispose()`.

您可以通過調用此類Session和方法OpenClose來改善命名。 此類的用戶不需要知道它是包裝器。 這只是一個實現細節。 而且,這些方法的命名現在是對稱的,無需重復使用Session名稱。

通過封裝所有與會話相關的內容,包括錯誤處理,從錯誤情況中恢復以及資源的處置,您可以大大減少代碼中的混亂情況。 Session類現在是一個高級抽象。 舊的DllWrapper介於低級和高級之間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM