gpt4 book ai didi

c# - 如何构造一个 try-catch-finally block 来处理 finally 内部的错误?

转载 作者:行者123 更新时间:2023-12-03 08:25:24 24 4
gpt4 key购买 nike

我在调用第三方 C++ dll 时遇到问题,我使用 DllImport 将其封装在一个类中访问其功能。

dll 要求在使用之前打开一个 session ,它返回一个整数句柄,用于在执行操作时引用该 session 。完成后,必须使用相同的句柄关闭 session 。所以我做了这样的事情:

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: One or more errors occurred. ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.



我不确定我能做些什么来阻止这个错误,因为它似乎是由以线程方式使用 Dll 引起的——它应该是线程安全的。但是由于我的 CloseSession() 函数除了调用 Dll 的 close 函数之外什么都不做,所以我没有太多的回旋余地来“修复”任何东西。

然而,最终结果是 session 没有正确关闭。因此,当该进程再次尝试时,它应该这样做,它会遇到一个打开的 session 并不断抛出新的错误。该 session 绝对必须关闭。

我不知道如何设计一个更强大的错误处理语句,以确保 session 始终关闭?

最佳答案

我会更改包装器以包括处理外部资源并包装句柄。 IE。不是用句柄来表示 session ,而是用包装器对象来表示它。

此外,将对 DLL 的调用封装在 lock 中。 -statements (正如@Serge 建议的那样),可以完全防止多线程问题。请注意,锁定对象是静态的,因此所有 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();
}
}

请注意,这些方法现在是实例方法。

现在您可以使用 using 语句确保 session 关闭:
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 相关的内容,包括错误处理、从错误情况中恢复和资源处理,您可以大大减少代码中的困惑。 Session类现在是一个高级抽象。老 DllWrapper处于低级和高级之间的中间距离。

关于c# - 如何构造一个 try-catch-finally block 来处理 finally 内部的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43474225/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com