令人惊讶的我才能够找到SO关于这个主题的一个先前的问题,我只是想获得社会"信任投票"(或不!)我的做法.
我这样看是这样的:
用Debug.Assert
你的处置将是真实的状态的事情.当我们完全控制我们的环境时,例如在验证某些前后条件的方法中,将使用此方法.
在出现特殊情况时使用例外情况.处理外部资源,即文件,数据库,网络等是很容易的.但...
在以下场景中它有点模糊.请注意,这是一个仅供参考的示例!
假设我们有MyClass类,它有一个公共属性MyMode和一个方法GetSomeValueForCurrentMode()
.将MyClass视为一个打算在库中发布(发布版本)以供其他开发人员使用的版本.
我们希望MyMode可以由此类的外部用户更新.现在,GetSomeValueForCurrentMode()
有以下逻辑:
switch(MyMode) { case Mode.ModeA: return val1; case Mode.ModeB: return val2; default: //Uh-uh this should never happen }
我在这里得到的是MyClass的用户将其置于无效状态.那我们该怎么办?
在默认情况下,我们应该Debug.Assert
或throw new InvalidOperationException
(或其他)?
有一句咒语说我们不应该信任我们班级的用户.如果我们选择Debug.Assert并将MyClass构建为发布版本(从而删除Debug Asserts),则该类的用户将无法获得他们将其置于无效状态的有用信息.但这与其他咒语相反,后者只表示在完全无法控制的事情发生时抛出异常.
我发现我围绕着这个问题 - 其中一个编程辩论似乎没有明确的'正确'答案.那么让我们投票吧!
编辑:我在相关的SO问题(使用断言或例外的合同设计?)中注意到了这个响应:
经验法则是,在尝试捕获自己的错误时应使用断言,在尝试捕获其他人的错误时应使用异常.换句话说,您应该使用异常来检查公共API函数的前提条件,以及何时获得系统外部的任何数据.您应该将断言用于系统内部的函数或数据.
对我而言,这是有道理的,并且可以与下面概述的'Assert then throw'技术结合使用.
欢迎思考!
首先,MyClass有效当然应该由MyClass的不变量表示.
其次,你说"我们期望MyMode由这个类的外部用户更新" - 当然这个模式的setter应该具有典型的按合同设计形式(如任何公共函数):
void Setter(mode m) { // INVARIANT ASSERT (1) // PRECONDITION ASSERTS (uses "m") (2) // BODY (3) // POSTCONDITION ASSERTS (if any) (4) // INVARIANT ASSERT (5) }
在(5)中,你会因为不变量不成立的尖叫断言而失败.但是在(2)中你会失败,因为传递的模式m是无效的.这将向用户发送明确的消息,从而解决您的问题.
请不要告诉我模式字段是公共的,用户在没有任何控制的情况下进行更改.
编辑:关于断言和释放模式,另请参阅:
断言总是坏的吗?
什么时候断言应该留在生产代码中?
使用断言或例外通过合同设计?
我基本上你自己的问题的结论一致:如果一个虱子的代码检测到错误一个虱子做,这是一个案例一个 ssert(和断言应在生产代码留下,除非性能另有规定).如果Alice的代码检测到E ve 代码中的错误,那么就是E xceptions 的情况,假设Alice和Eve位于错误跟踪软件的两侧.
现在这是一般的经验法则.断言,略有修改的形式,也可以用作"单挑,开发人员!"机制(然后它们不应被称为"ASSERT",而是"HEADS_UP"或类似的东西).如果您的公司开发客户端/服务器产品,并且服务器向客户端发送无效数据,该怎么办?如果您是客户端程序员,您会觉得将其视为外部数据(这是Eve的数据是kaputt)并且您想要抛出异常.但是,一个"更软"的断言,使Visual Studio的调试器停在那里,可以很早地检测到这些问题并将其报告给服务器团队.在一个真正的装置中,很可能是Mallory使用Eve和Alice之间的数据进行调整,但大部分时间它都是你的同事之一的错误,并且你想在它发生的时候看到它 - 这就是我称它们为什么的原因"单挑"断言:他们'不'
我同意这里的大多数人并遵循"按合同设计".您应该尝试区分已部署代码(合同)中的要求和设计期间的预期状态(调试断言).
您应该始终将合同断言作为例外(因为它们应该始终是例外).大多数框架都内置了用于捕获调试断言的机制.但在运行时,您应该总是抛出异常.
我使用自定义库来帮助解决这个问题(在C#/ VB.NET中).我最近在Codeplex(http://www.contractdriven.com/)上提出了它,如果你对它在实践中是如何工作感兴趣的话.
这样做的另一个好处是,当您开始更频繁地使用DbC时,您很少需要使用调试断言,因为已经有明确的保证写入您的代码,因此实际上很难进入无效状态.
所以你原来的帖子中的问题......"我在这里得到的是MyClass的用户将其置于无效状态.那么我们该怎么办?"......永远不应该出现.
您可能永远不需要再次调试任何东西!;-)