gpt4 book ai didi

c# - C# 中简化的类 C 宏函数调用

转载 作者:太空宇宙 更新时间:2023-11-03 10:43:00 25 4
gpt4 key购买 nike

我正在为 C dll 编写包装器。为 C# 应用程序包装了各种 C 函数。现在考虑下面包装器的一些简化部分。

public enum ErrorCode
{
OK = 0,
...
...
}

public class AppException: ApplicationException
{
public AppException(ErrorCode errorCode) : base()
{
error = errorCode;
}

public ErrorCode error { get; private set; }
}

public class A
{
public ErrorCode last_ret;
private IntPtr datap;

public A(string filename)
{
last_ret = (ErrorCode)ClibDllFunc1(filename, out datap);
if (last_ret != ErrorCode.OK)
throw new AppException(last_ret);

// go on processing

last_ret = (ErrorCode)ClibDllFunc2(datap);
if (last_ret != ErrorCode.OK)
throw new AppException(last_ret);
}

public void getSize(out int sz)
{
last_ret = (ErrorCode)ClibDllFunc3(datap, out sz);
if (last_ret != ErrorCode.OK)
throw new AppException(last_ret);
}

// ...
// many functions like these, all working by calling c/c++ dll functions
// with different number and types of parameters
}

[DllImport("clibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
static extern internal int ClibDllFunc1(string filename, out IntPtr data);

// ... other C function declarations follow similarly

如您所见,包装器调用各种 C 函数。所有 C 函数都返回整数作为状态代码(错误代码),包装器必须检查此返回代码并在 C 函数失败时抛出应用程序定义的异常。对于所有 C 函数调用,这必须以完全相同的方式完成。只有函数名称和参数发生变化,但 3 行调用 block 是相同的。这种形式看起来非常便宜,因为复制/粘贴了 3 行函数调用 block 。

在C#中,有没有办法将“调用、检查返回码、抛出异常”的循环简化和封装成更简单紧凑的方式?

供引用(实际上这是我想做的来简化调用);在 C/C++ 中,我们可以定义这样一个宏:

#define SAFE_CALL(call) do{ if((last_ret = (ErrorCode)call) != OK) throw AppException(last_ret); }while(0)

然后这样调用:

SAFE_CALL(ClibDllFunc1(filename, &datap));
SAFE_CALL(ClibDllFunc2(datap));
SAFE_CALL(ClibDllFunc3(datap, &sz));

最佳答案

编辑

重新阅读你的问题,我回答了错误的问题。您真正想要的是一个采用 int 的函数 CheckErrorCode,然后简单地传递 native 调用的结果。

/// <summary>
/// Takes the result code from invoking a native function. If the result is
/// not ErrorCode.OK, throws an AppException with that error code.
/// </summary>
/// <param name="returnCodeInt">
/// The return code of a native method call, as an integer.
/// Will be cast to ErrorCode.
/// </param>
private static void CheckErrorCode(int returnCodeInt)
{
ErrorCode returnCode = (ErrorCode)returnCodeInt;
if(returnCode != ErrorCode.OK)
{
throw new AppException(returnCode);
}
}

public void getSize(out int sz)
{
CheckErrorCode(ClibDllFunc3(datap, out sz));
}

原文(如何用lambdas模拟宏)

事实上,C# 中的 lambda 语法非常简洁,这意味着您可以使用 Func<T>以类似于宏的方式。尝试这样的事情:

/// <summary>
/// Calls a function's native implementation, then checks if the error code
/// is not ErrorCode.Ok. If it is, throws an AppException.
/// </summary>
/// <param name="nativeCall">
/// A function that returns the status code as an int.
/// </param>
private static void CheckErrorCode(Func<int> nativeCall)
{
var returnCode = (ErrorCode)nativeCall();
if(returnCode != ErrorCode.OK)
{
throw new AppException(returnCode);
}
}

然后你可以调用它:

public void getSize(out int sz)
{
// drawback: compiler can't check that sz is always written.
sz = 0;
CheckErrorCode(() => ClibDllFunc3(datap, out sz));
}

lambda 创建了所谓的 closure .这是一种将调用 ClibDllFunc3(特定于此函数)的逻辑从处理其结果(这是所有 DLL 函数的标准)的逻辑中拉出来的方法。与许多闭包不同,这个闭包会立即被调用。

关于c# - C# 中简化的类 C 宏函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24603044/

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