异常错误码

Errorcodes in exception

我有一个专有的 C# 库,它基本上是一些 C++ 代码的包装器。 它提供的功能如下所示:

public int func(in params, out params...)

返回的 int 表示成功 (0)、一些错误代码 (<0) 或一些数据(>0,例如成功读取的字节数)。 此外,该库还提供了一个 public EnumErrorCode GetLastError() 函数

我的任务是编写另一个包装器,将每个带有错误代码的函数转换为抛出异常的函数

虽然returncode很容易进入异常

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-文档提供)并在创建函数

中为 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);
    }
    
}

首先:重申评论中的观点:

  • 如果你需要它是线程安全的,你需要对你的客户进行“原子”调用。
  • 为了安全起见,我会用另一个 try/catch 将 GetLastError 括起来。

使用第 3 方枚举

这取决于您想对适配器的客户端隐藏第 3 方的程度。 如果他们不应该知道第 3 方(至少在使用您的适配器时,当然,他们可能 知道 有第 3 方),那么您需要隐藏原始枚举。

这可以通过制作您自己的该枚举的“副本”来完成。这是可能的,但它有严重的缺陷:在第 3 方的每次更新中,您需要检查枚举是否已更改并相应地更改 您的代码 甚至可以 导致重大更改。

我过去所做的只是使用和公开整数值并提供一个 ErrorCodeToString 函数,该函数基本上将 int 转换为第 3 方枚举,然后执行 ToString。这对我的目的来说已经足够了,但我当然不会声称这是 the 甚至 a“最佳实践”。

创建例外

回顾一下我们拥有的:

  • 函数可以有 return 个代码
    • 0 ==“好的”
    • >0(只有其中一些)== 一些整数值的结果。
    • <0 ,其中...
      • '-1'是所有函数共有的常见错误
      • '-2' 及更小的是特定于函数的错误(每个函数的含义不同)
  • 在负 return 代码之上,可以通过调用 GetLastError.
  • 检索错误代码(=> 枚举)

现在,一个问题是:除了仅具有 ErrorCodeEnum 值之外,维护所有功能特定 return 代码的耗尽 table 是否有益?

如果是:事情变得有点复杂。但也许我们现在可以 暂时搁置这个 并专注于枚举值。

当然,您不想为每个函数都编写自定义处理。所以,你想要的是某种异常工厂。

我对此的假设是:

  • 您可能想为每个枚举值分配不同的异常消息。
  • 您已经展示了自定义 MyException 类型,因此您可能想要使用它。

现在,您需要做出设计决定。您可以使用 one 异常类型并使其具有属性。或者您可以从基本异常类型派生“子”类型。

后者可以方便地将您 want/need 处理的异常与您(或客户)只想“冒泡”的其他异常进行分组或挑出。

无论哪种方式,您都希望有一个像

这样的界面
public interface IMyExceptionFactory
{
    MyException Create(int returnCode, int errorCode);
}

在你的适配器中使用(我想你会想要注入它),这样它就可以发挥它的魔力,你可以扔掉它给你的任何东西。

例如:

// snip
int returnCode = CallToThirdParty();
if( returnCode < 0 )
{
    int errorCode = GetLastError();
    throw _exceptionFactory.Create(returnCode, errorCode);
}

在其实现中,您将构建适当的异常消息(可能是派生类型)并将其他属性设置为正确的值。

例如,您可以构建一个字典,让您通过错误代码等查找消息。然后您可以决定是通过硬编码还是通过配置来构建...