我正在围绕一个相当大的非托管 API 编写一个包装器。几乎每个导入的方法在失败时都会返回一个常见的错误代码。现在,我正在这样做:
ErrorCode result = Api.Method();
if (result != ErrorCode.SUCCESS) {
throw Helper.ErrorToException(result);
}
这很好用。问题是,我有很多非托管方法调用,这变得非常令人沮丧和重复。所以,我尝试切换到这个:
public static void ApiCall(Func<ErrorCode> apiMethod) {
ErrorCode result = apiMethod();
if (result != ErrorCode.SUCCESS) {
throw Helper.ErrorToException(result);
}
}
这使我可以将所有这些呼叫减少到一条线路:
Helper.ApiCall(() => Api.Method());
然而,这有两个直接问题。首先,如果我的非托管方法使用out
参数,我必须首先初始化局部变量,因为方法调用实际上是在委托中。我希望能够简单地声明一个out
目的地而不初始化它。
其次,如果抛出异常,我真的不知道它是从哪里来的。调试器跳转到ApiCall
方法和堆栈跟踪仅显示包含调用的方法ApiCall
而不是代表本身。由于我可以在一个方法中进行许多 API 调用,这使得调试变得困难。
然后我考虑使用 PostSharp 通过错误代码检查来包装所有非托管调用,但我不确定如何完成extern
方法。如果它最终只是为每个方法创建一个包装方法,那么我将遇到与ApiCall
方法对吧?另外,如果调试器仅存在于已编译的程序集中,那么调试器如何知道如何向我显示代码中引发异常的位置?
接下来,我尝试实现一个自定义封送拆收器,该封送拆收器将拦截 API 调用的返回值并检查其中的错误代码。不幸的是,您无法应用自定义封送拆收器来返回值。但我认为,如果可行的话,这将是一个非常干净的解决方案。
[return:
MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ApiMethod))]
public static extern ErrorCode Method();
现在我完全没有想法了。我还可以通过哪些其他方法来处理这个问题?