【发布时间】:2021-08-31 06:52:24
【问题描述】:
我有一个专有的 C# 库,它基本上是一些 C++ 代码的包装器。 它提供的功能如下所示:
public int func(in params, out params...)
返回的 int 表示成功(0)、一些错误代码(0,例如成功读取的字节数)。
此外,该库还提供了一个public EnumErrorCode GetLastError() 函数
我的任务是编写另一个包装器,它将带有错误代码的每个函数转换为引发异常的函数
虽然很容易将返回码放入异常中
public class MyException : Exception
{
public int RetVal { get; }
public MyException(int retVal) : { RetVal = retVal;}
public MyException(string message, int retVal) : base(message) { RetVal = retVal; }
}
习惯了
public void func(int a)
{
var retVal = api.func(a);
switch (retVal)
{
case 0: return;
case -1: throw new MyException("same error across all funcs", retVal);
case -2: throw new MyException("func specific error", retVal);
default: throw new MyException(retVal);
}
}
我很难找到正确的方法来让 EnumErrorCode GetLastError() 进入异常
首先,我应该引入一个新属性public EnumErrorCode ErrorCode { get; },在专有的 C# 库中定义 EnumErrorCode,还是应该只存储一个 int?
其次,在抛出异常的同时调用GetLastError()可以吗?
case -1: throw new MyException("Mayhem!", retVal, GetLastError());
在抛出时再次调用外部未知代码似乎是不对的。还有哪些可能?
感谢 Fildor 的详细回答。 我想我会混入那个特定于函数的消息(由 API 文档提供),并在 Create 函数中为 EnumErrorCode 映射使用字典
public interface IMyExceptionFactory
{
MyException Create(string funcSpecificCodeMsg, int returnCode, int errorCode);
}
// snip
int returnCode = CallToThirdParty();
if (returnCode < 0)
{
int errorCode = -1;
try
{
errorCode = (int)GetLastError();
}
catch (Exception) { }
switch (returnCode)
{
case -1: throw _exceptionFactory.Create("invalid handle", returnCode, errorCode);
case -2: throw _exceptionFactory.Create("func specific error -2", returnCode, errorCode);
...
default: throw _exceptionFactory.Create("Unknown returnCode", returnCode, errorCode);
}
}
【问题讨论】:
-
如果您需要它是线程安全的,您需要对您的客户进行“原子”调用。另外,为了安全起见,我会在
GetLastError中加上另一个 try/catch。 -
关于 Enum 的事情:你需要/想要完全隐藏第 3 方吗?然后不要使用 Enum 而只是使用它的 int 表示。请注意这对您的客户意味着什么。如果您想要一个更“可读”的值的便利,您可以创建一个函数,返回枚举值的“ToString”(例如,当然还有更多选项)。
-
所有第 3 方 API 的错误代码是否一致?或者错误代码是特定于函数的(= 每个函数都有自己的一组错误代码,在不同的函数上,相同的代码可以有不同的语义)?如果只有一组错误代码,我会将其排除并创建一个异常工厂。
-
最后:请注意,在您的实施中,您会忽略积极的结果。这将默认抛出
MyException(retVal)。好像不太对? -
如果本机库为错误代码声明了一个枚举,那么您对错误原因了解很多。因此,您只需要 MyException(int) 构造函数,并且可以将错误代码转换为构造函数内的描述性字符串。最后一条语句就好了,GetLastError 被调用之前抛出异常,越早越好。