假设您正在使用返回错误代码的库。您想为库编写一个包装器,并且您希望在代码中处理包含异常的错误。
如果该库仍在由其他人开发,并且错误代码可能会更改(可能有新的错误代码,可能会有弃用代码,或者某些错误代码可能会稍微改变含义),您的解决方案是什么?处理这个?
这就是我现在所处的情况。在我的例子中,库是用C ++编写的,我们使用的是C#。该库的编码器说错误代码可能会改变,我必须找到一种方法来处理它。
我们最初的解决方案是:
因此,假设一个方法返回错误代码100,然后包装器检查错误代码的类别。如果是终端错误则抛出终端错误异常,如果是用户输入错误则抛出用户输入错误例外
这应该有效,但我觉得这不是最佳解决方案。我想知道编写的企业软件如何处理错误代码的更改。
你会建议做什么?
编辑:我已经质疑错误代码会发生变化这一事实,而且编码器的编码器说代码正在开发中。这是一种算法,所以即使算法的工作方式也会因为它的原始研究而改变(他正在撰写博士论文)。所以他说可能会有不同的错误,或者有些可能在将来无关紧要。
答案 0 :(得分:5)
根据具体情况,使用XML文件的数据驱动方法似乎是一个很好的方法。但是我会质疑为什么错误代码会发生变化 - 这表明没有对正在开发的库进行适当的设计。它的错误代码应该有一个明确定义的结构,而不是要求你不断改变对它们的解释。
您可能希望尝试使用整体“库异常”异常类,并根据库错误的“类型”为要抛出的每种不同类型的异常创建子类。至少在这种情况下,您可以捕获所有库错误,即使其中一种特定类型的异常通过网络传输。即。在尝试捕捉LibraryException
后,你会发现TerminalErrorException
之类的东西。
答案 1 :(得分:3)
如果你稍微改变一下你对这种情况的看法,我想你会更容易解决这个问题:
现在,问题归结为以下问题:内部框架的功能是否已明确概述并最终确定?还是会改变?
如果它正在发生变化(可能是因为外部框架),那么内部框架正在开发中。这意味着,客户端应用程序需要等待内部框架准备好宣布第一个版本就绪(可能在外部框架完成之后)。
现在错误处理:
应用程序中的错误类似于合同。函数的调用者需要特殊的特殊情况,以及特殊类型的错误仅。每个可能的错误都是由每个函数预定义和记录的,类似于它的输入参数和返回值。
对您来说意味着什么:
为什么最后的假设很好?因为我们说内部应用程序的设计是最终的,不会改变。错误契约也是最终设计的一部分。
示例:强>
//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或任何类型的源存储类似的句子,这将帮助您配置错误转换规则和函数契约。
<强>参考强>
预订:杰弗里里希特 - CLR通过C#,第3版。第20章 - 例外与国家管理。分章 - 指南和最佳实践。小分章 - 隐藏实施细则以维持“合同”。
本章将异常描述为合同,并将解释如何对函数抛出的合同进行分类。这可以确认这里提供的解释的正确性和可信度。
答案 2 :(得分: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使用Reflection创建特定异常的实例。
我更喜欢CustomExceptionFactory&amp; BaseCustomException将在汇编中实现
并且所有派生的CustomExceptions都在另一个程序集中实现,因此我们的主应用程序与CustomExceptions.Dll无关
在未来通过改变C ++工厂,我们的主要应用程序将不需要重建,我们所需要的只是在CustomExceptions.Dll中更改表和数据的数据。
(可以使用XML或配置文件实现相同的解决方案或......)
跳这将有所帮助。
答案 3 :(得分:0)
好的,如果你想要灵活而不依赖代码,我认为在你第一次运行应用程序时使用反射生成自定义类将是最好的。这是粗略的解释。如果你喜欢它我可以进一步解释。 C ++代码的提供者应该创建一个包含所有错误代码的类 - 例如公共类错误{public static readonly IOError = 100}。 当您启动应用程序时,您将检查此类以进行修改,如果它被修改,您将为每个错误代码生成异常类。 在上面的示例中,您将生成继承Exception .net类的类IoException。 之后,您可以在包装器中使用它并单独捕获每个异常。 另一个可能的解决方案是修改你提到的xml - 为每个错误代码添加异常类 - 使用示例对于错误代码100,你将拥有IoException类。之后你需要实现这个类并使用它......
答案 4 :(得分:0)
最好贬低旧代码并保留其名称,而不是让代码名称不断变化。由于您的作者似乎对设计不感兴趣,请让他在您可以检索的stderr
流上报告警告和错误。
此外,构建具有代码串对的CSV或XML似乎很简单,算法编写者可以根据需要自由编辑。为不同的类型错误保留某些范围的代码编号(输入错误为1000s,终端错误为2000s等),包装器使用他编写的代码串对解释返回代码。
然后根据由数字范围确定的错误类型抛出异常。