C# 如何构造try-catch-finally块来处理finally中的错误? 我在使用第三方C++ DLL调用DLIMPRATE来访问其函数时遇到了一个问题。

C# 如何构造try-catch-finally块来处理finally中的错误? 我在使用第三方C++ DLL调用DLIMPRATE来访问其函数时遇到了一个问题。,c#,multithreading,dll,error-handling,unmanaged,C#,Multithreading,Dll,Error Handling,Unmanaged,dll要求在使用之前打开一个会话,该会话返回一个整数句柄,用于在执行操作时引用该会话。完成后,必须使用相同的句柄关闭会话。所以我做了这样的事情: public void DoWork(string input) { int apiHandle = DllWrapper.StartSession(); try { // do work using the apiHandle } catch(ApplicationException ex)

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引起的——它应该是线程安全的。但是由于我的closesesession函数除了调用Dll的close函数外什么都不做,所以我没有太多的空间来修复任何东西

然而,最终的结果是会话无法正常关闭。因此,当进程再次尝试时,它会遇到一个打开的会话,并不断抛出新的错误。该届会议绝对必须结束


我不知道如何设计一个更健壮的错误处理语句,以确保会话始终关闭?

我将更改包装,以包括外部资源的处置,并包装句柄。也就是说,不是用句柄表示会话,而是用包装器对象表示会话

此外,按照@Serge的建议,将对DLL的调用封装在lock语句中,可以完全防止多线程问题。请注意,锁定对象是静态的,因此所有DLLWRAPPER都使用相同的锁定对象

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();
     }
}
您可以通过调用这个类会话和方法Open和Close来改进命名。这个类的用户不需要知道它是一个包装器。这只是一个实现细节。此外,方法的命名现在是对称的,不需要重复命名会话


通过封装所有与会话相关的内容,包括错误处理、从错误情况中恢复和资源处置,您可以大大减少代码中的混乱。会话类现在是一个高级抽象。旧的DllWrapper位于低级和高级之间的中间位置。

我想问题是,应该如何处理错误?如果关闭会话会引发来自第三方代码的错误,并且我们无法在不关闭会话的情况下继续,那么接下来该怎么办?我的意思是,你可以在最后再尝试一次,但是你会如何应对这个错误呢?如果第三方工具不起作用,怎么办?如果这是由线程引起的,那么也许您可以通过使用有关StartSession和CloseSession方法调用的语句来解决问题。@David第三方工具失败是间歇性的-当您第二次尝试时,它通常会起作用。我的实际代码目前是一堆糟糕的递归和控制流,试图确保这种情况总是发生。我不想添加更多内容,但如果必须添加,我必须添加:@mattstrower您是否已经使用这个并非真正线程安全的第三方库一次只通过一个线程进行了测试?如果这样做,问题会消失吗?这是32位还是64位DLL?句柄通常是指针大小的东西。您可能应该使用IntPtr而不是int作为句柄类型。谢谢。我非常喜欢将它作为一种解决问题的方法,同时整理代码。使用这种方法的初始原型似乎大大降低了处理速度,我不知道为什么。我正在调查-如果我能解决问题,我会很乐意接受的。
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()`.