11

假设您正在使用一个返回错误代码的库。您想为该库编写一个包装器,并且您想处理代码中出现异常的错误。

如果该库仍在由其他人开发,并且错误代码可能会更改(可能有新代码,可能有已弃用的代码,或者某些错误代码可能会稍微改变含义),您的解决方案是什么?

这就是我现在的情况。就我而言,该库是用 C++ 编写的,而我们使用的是 C#。图书馆的编码员说错误代码可能会改变,我必须找到一种方法来处理它。

我们最初的解决方案是:

  1. 创建一个包含不同类别的错误代码(终端错误、输入错误等)的 XML 文件。
  2. Wrapper 在启动时获取这些错误代码。
  3. 通过检查错误代码的类别引发适当的异常。

假设一个方法返回错误代码 100,然后包装器检查错误代码的类别。如果是终端错误,则抛出终端错误异常,如果是用户输入错误,则抛出用户输入错误异常

这应该可行,但我觉得这不是最佳解决方案。我想知道编写好的企业软件如何处理错误代码的变化。

你会建议做什么?

编辑:我已经质疑错误代码将发生变化的事实,并且库的编码人员说代码正在开发中。这是一种算法,所以即使是算法的工作方式也会随着它的原始研究而改变(他正在为此撰写博士学位)。所以他说可能会有不同的错误,或者将来可能不相关。

4

5 回答 5

5

考虑到具体情况,您正在采用的使用 XML 文件的数据驱动方法似乎是一种不错的方法。但是我会质疑为什么错误代码会发生变化 - 这表明没有为正在开发的库进行适当的设计。它的错误代码应该有一个明确定义的结构,而不是要求你不断改变对它们的解释。

您可能想尝试拥有一个整体的“库异常”异常类,并根据库错误的“类型”为要抛出的每种不同类型的异常对其进行子类化。至少这样,您可以捕获所有库错误,即使其中一种特定类型的异常漏网了。IE。LibraryException你会在尝试 catch 之后捕捉到类似的东西TerminalErrorException

于 2013-01-31T11:13:36.590 回答
3

我想如果你稍微改变一下你对情况的看法,你会更容易解决这个问题:

  1. 您正在处理框架,我们称其为外部框架。
  2. 另一方面,您正在为框架编写一个包装器 - 内部框架。
  3. 您的代码(客户端应用程序)使用内部框架,假设它提供用于问题域的功能。据我了解,并且我相信,客户端应用程序不应该对外部框架有任何想法。

现在,问题归结为以下一个问题:内部框架的功能是否明确概述并最终确定?还是这也在改变?

如果它正在改变(可能是因为外部框架),那么内部框架正在开发中。这意味着,客户端应用程序需要等到内部框架准备好宣布第一个版本准备就绪(可能在外部框架完成之后)。

现在错误处理:

应用程序中的错误就像合同一样。函数的调用者只期望特定的异常情况和特定类型的错误。每个可能的错误都由每个函数预定义和记录,类似于它的输入参数和返回值。

这对您意味着什么:

  1. 定义内部框架的最终设计(越早越好)。
  2. 决定内部框架的每个函数可以抛出什么样的错误。
  3. 使用客户端应用程序的内部框架,只期望预期和记录的异常。不要尝试/捕获内部框架不期望的任何内容。基本上,遵守合同。
  4. 如果错误代码发生变化,则不会改变内部框架中函数的概念。它仍然需要抛出它之前抛出的相同类型的错误(根据合同)。唯一需要更改的部分是,如何将新代码转换为预期的(约定的)错误之一。你可以用任何更好的方法来解决它。

为什么最后一个假设是好的?因为我们说过内部应用程序的设计是最终的,不会改变。错误合约也是最终设计的一部分。

例子:

//external.
int Say(char* message);

//internal.
///<summary>
/// can throw (CONTRACT): WrongMessageException, SessionTimeOutException
void Say(string message) {
    int errorCode = External.Say(message);
    //translate error code to either WrongMessageException or to SessionTimeOutException.
}

不能翻译?当前的约定错误或外部框架有问题:也许您应该终止该过程?出事了,没想到!!!

//client.
...
try {
    Internal.Say("Hello");
}
catch (WrongMessageException wme) {
    //deal with wrong message situation.
}
catch (SessionTimeOutException stoe) {
    //deal with session timeout situation.
}

让我知道是否有任何问题。

将错误代码转换为异常:

这显然是对每个错误代码的某种分类。类别可以是每个目的地异常,并且可以按功能对异常进行分类。这正是错误合约的含义:按功能对异常进行分类;并按异常对错误代码进行分类。

下面是一个伪配置。以此作为如何分类的初步想法:

category Say [can throw]: { WrongMessageException, SessionTimeOutException }
category WrongMessageException [by error code]: { 100, 101 }
category SessionTimeOutException [by error code]: { 102, 103, 104 }

当然,您不需要为这种印象编写解析器(这是人类可读的伪配置)。您可以使用 XML 或任何类型的源存储类似的句子,这将帮助您配置错误翻译规则和函数契约。

参考

书籍:Jeffrey Richter - CLR 通过 C#,第 3 版。第 20 章 - 异常和状态管理。子章 - 指南和最佳实践。Sub-Sub-Chapter - 隐藏实施细节以维护“合同”。

本章将把异常描述为契约,并将解释如何对函数抛出的契约进行分类。这可以确认这里提供的解释的正确性和可信度。

于 2013-02-07T18:10:25.363 回答
1

那这个呢:

您说您已将错误类别存储在某个位置(DB 或 XML 文件)让我们有一些
名为 ErrorCategory(Master) 和 ErrorDetail(Detail) 的主详细信息表
我会建议在您的 Errorcategory 表中添加一个列(属性),称为CustomExceptionType,它将是一个文本属性,包含程序集的全名和指定异常的类名(例如:CustomExceptions,CustomExceptions.TerminalError
我们需要一个基类 4 我们所有的自定义异常,让我们调用它BaseCustomException calss
我们需要一个 ExceptionFactory 类让我们调用它CustomExceptionFactory class
我们的 ExceptionFactory 将有一个名为 CreateException 的方法,类似于这样

Public BaseCustomException CreateException(EceptinCategory category, ExceptionDetail detail)
{
   var customException = Activator.CreateInstance(category.CustomExceptionType) as      BaseCustomException;
   customException.SetDetails(detail);
   return customException;
}

因此在运行时,我们的 CustomExceptionFactory 对象将使用 CustomExceptionType 使用反射创建特定异常的实例。
我更喜欢 CustomExceptionFactory 和 BaseCustomException 在一个程序集中实现,所有派生的 CustomExceptions 在另一个程序集中实现,因此我们的主应用程序将与 CustomExceptions.Dll 不相关 将来
通过更改 C++ 工厂,我们的主应用程序将不需要重建,我们所有的需要在CustomExceptions.Dll 中改变表格和impementaion 的数据。(可以使用 XML 或配置文件来实现相同的解决方案,或者......)

跳这会有所帮助。

于 2013-02-08T21:46:16.847 回答
0

好的,如果您想要灵活并且不依赖于代码,我认为在您首次运行应用程序时使用反射生成自定义类是最好的。这是粗略的解释。如果你喜欢它,我可以进一步解释。C++ 代码的提供者应该创建一个包含所有错误代码的类 - 例如 public class Errors{public static readonly IOError = 100}。当您启动您的应用程序时,您将检查此类是否有修改,如果它被修改,您将为每个错误代码生成异常类。在上面的示例中,您将生成继承 Exception .net 类的类 IoException。之后,您可以在包装器中使用它并单独捕获每个异常。另一种可能的解决方案是修改您提到的 xml - 为每个错误代码添加异常类 - 使用错误代码 100 的示例,您将拥有 IoException 类。之后你需要实现这个类并使用它......

于 2013-02-02T20:29:06.953 回答
0

最好折旧旧代码并保留其名称,而不是让您的代码名称不断变化。由于您的作者似乎对设计不感兴趣,请让他报告stderr您可以检索的流上的警告和错误。

此外,用代码字符串对构建 CSV 或 XML 似乎很简单,算法编写者可以自由编辑他认为合适的内容。为不同类型的错误保留一定范围的代码编号(1000s 用于输入错误,2000s 用于终端错误等)让您的包装器使用他编写的代码字符串对来解释返回代码。

然后根据错误类型抛出异常,由数字范围确定。

于 2013-02-05T20:39:13.790 回答