gpt4 book ai didi

c# - 您如何验证对象的内部状态?

转载 作者:可可西里 更新时间:2023-11-01 18:27:48 26 4
gpt4 key购买 nike

我很想听听您在操作期间使用什么技术来验证对象的内部状态,从它自己的角度来看,只有内部状态不佳或不变破坏才会失败。

我的主要关注点是 C++,因为在 C# 中,官方和流行的方法是抛出异常,而在 C++ 中,不止一种单一方法可以做到这一点(好吧,在 C# 中不是这样要么,我知道)。

请注意,我不是在谈论函数参数验证,而更像是类不变完整性检查。

例如,假设我们想要一个 Printer 对象异步地Queue 打印作业。对于 Printer 的用户来说,该操作只能成功,因为异步队列结果会在另一个时间到达。因此,没有相关的错误代码可以传达给调用者。

但是对于 Printer 对象,如果内部状态不好,这个操作可能会失败,即类不变量被破坏,这基本上意味着:一个错误。 Printer 对象的用户不一定对这种情况感兴趣。

就个人而言,我倾向于混合使用三种内部状态验证方式,我无法真正确定哪一种是最好的(如果有的话),只能确定哪一种绝对是最差的。我想听听您对这些的看法,也希望您分享您对此事的任何经验和想法。

我使用的第一种风格 - 以可控的方式失败比损坏数据更好:

void Printer::Queue(const PrintJob& job)
{
// Validate the state in both release and debug builds.
// Never proceed with the queuing in a bad state.
if(!IsValidState())
{
throw InvalidOperationException();
}

// Continue with queuing, parameter checking, etc.
// Internal state is guaranteed to be good.
}

我使用的第二种风格 - 比损坏数据更好的崩溃无法控制:

void Printer::Queue(const PrintJob& job)
{
// Validate the state in debug builds only.
// Break into the debugger in debug builds.
// Always proceed with the queuing, also in a bad state.
DebugAssert(IsValidState());

// Continue with queuing, parameter checking, etc.
// Generally, behavior is now undefined, because of bad internal state.
// But, specifically, this often means an access violation when
// a NULL pointer is dereferenced, or something similar, and that crash will
// generate a dump file that can be used to find the error cause during
// testing before shipping the product.
}

我使用的第三种方式 - 比损坏的数据更好的静默和防御性救助:

void Printer::Queue(const PrintJob& job)
{
// Validate the state in both release and debug builds.
// Break into the debugger in debug builds.
// Never proceed with the queuing in a bad state.
// This object will likely never again succeed in queuing anything.
if(!IsValidState())
{
DebugBreak();
return;
}

// Continue with defenestration.
// Internal state is guaranteed to be good.
}

我对样式的评论:

  1. 我想我更喜欢第二种方式,这种方式不会隐藏故障,前提是访问冲突实际上会导致崩溃。
  2. 如果不涉及不变量的NULL指针,那么我倾向于第一种方式。
  3. 我真的不喜欢第三种风格,因为它会隐藏很多错误,但我知道有人在生产代码中更喜欢它,因为它创造了一种不会崩溃的健壮软件的错觉(功能将停止运行,就像在损坏的 Printer 对象上排队一样)。

您更喜欢这些中的任何一个,或者您有其他实现方法吗?

最佳答案

您可以将称为 NVI(非虚拟接口(interface))的技术与模板方法 模式结合使用。我大概是这样(当然,这只是我个人的看法,确实值得商榷):

class Printer {
public:
// checks invariant, and calls the actual queuing
void Queue(const PrintJob&);
private:
virtual void DoQueue(const PringJob&);
};


void Printer::Queue(const PrintJob& job) // not virtual
{
// Validate the state in both release and debug builds.
// Never proceed with the queuing in a bad state.
if(!IsValidState()) {
throw std::logic_error("Printer not ready");
}

// call virtual method DoQueue which does the job
DoQueue(job);
}

void Printer::DoQueue(const PrintJob& job) // virtual
{
// Do the actual Queuing. State is guaranteed to be valid.
}

因为 Queue 是非虚拟的,如果派生类覆盖 DoQueue 进行特殊处理,仍然会检查不变量。


关于您的选择:我认为这取决于您要检查的条件。

如果是内部不变量

If it is an invariant, it should not be possible for a user of your class to violate it. The class should care about its invariant itself. Therefor, i would assert(CheckInvariant()); in such a case.

它只是一个方法的前置条件

If it's merely a pre-condition that the user of the class would have to guarantee (say, only printing after the printer is ready), i would throw std::logic_error as shown above.

我真的不鼓励检查条件,但什么都不做。


类的用户可以在调用方法之前自行断言它的先决条件已得到满足。所以一般来说,如果一个类负责某个状态,并且它发现一个状态无效,它应该断言。如果类(class)发现违反了不属于其责任的条件,则应抛出。

关于c# - 您如何验证对象的内部状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/343605/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com