你错过了一个方法:返回失败指示并需要额外调用以获取错误的详细信息。
这个方法有很多值得称赞的地方。
例如:
int count;
if (!TryParse("12x3", &count))
DisplayError(GetLastError());
编辑
这个答案引起了相当多的争议和负评。坦白地说,我完全不被反对的论点所说服。将调用是否成功与失败原因分开已被证明是一个非常好的想法。将两者结合在一起会迫使你遵循以下模式:
HKEY key;
long errcode = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key);
if (errcode != ERROR_SUCCESS)
return DisplayError(errcode);
与此形成对比的是:
HKEY key;
if (!RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key))
return DisplayError(GetLastError());
(GetLastError版本与Windows API的工作方式一致,但直接返回代码的版本是实际工作方式,因为注册表API不遵循该标准。)
无论如何,我建议错误返回模式使人们很容易忘记函数失败的原因,导致出现以下代码:
HKEY key;
if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key) != ERROR_SUCCESS)
return DisplayGenericError();
编辑
看了 R. 的请求后,我找到了一个实际可以满足该请求的场景。
对于一个通用的 C 风格 API,例如在我的示例中使用的 Windows SDK 函数,没有非全局上下文可用来存储错误代码。因此,我们别无选择,只能使用一个全局的 TLV(类型-长度-值),以便在失败后进行检查。
但是,如果将范围扩展到类的方法,则情况就不同了。如果有一个变量 reg
是 RegistryKey
类的实例,那么调用 reg.Open
返回 false
就是完全合理的,这时需要调用 reg.ErrorCode
来检索详细信息。
我认为这样就满足了 R. 的关于错误代码作为上下文的要求,因为实例提供了上下文。如果我们不是调用 RegistryKey
实例,而是调用静态的 Open
方法,则在失败后检索错误代码也必须是静态的,这意味着它必须是一个 TLV,虽然不是完全全局的。类本身作为上下文。
在这两种情况下,面向对象编程提供了一个自然的上下文来存储错误代码。话虽如此,如果没有自然的上下文,我仍然会坚持使用全局变量,而不是试图强制调用者传递输出参数或其他人工上下文,或直接返回错误代码。