所以我有一个非常简单的类,其中一个字符串作为属性.该字符串必须具有某种模式.我正在尝试使用代码合同来强制执行此操作.该类看起来像这样:
class SimpleClass
{
public Property { get; set; }
public SimpleClass(string prop)
{
Contract.Requires(IsValid(prop));
this.Property = prop;
}
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(IsValid(Property));
}
bool IsValid(string arg)
{
// Use regex to check if arg is a valid string
}
}
Run Code Online (Sandbox Code Playgroud)
非常直截了当.但是,这会抛出一个不可读的异常,另一个说"Member SimpleClass.IsValid的可见性低于封闭方法SimpleClass.#ctor(System.String)".为什么这是非法的?我应该将正则表达式复制/粘贴到两种方法中吗?这似乎与正确相反.请帮我理解!
在契约式设计中,类不变量必须在两种情况下满足:创建对象之后和调用例程之后。是否有任何示例或条件,我也必须在调用例程之前进行评估?
因此,我们正在调查范围保护或类似机制的使用,以确保传入/传出对象的有效性和/或内部状态不变性,类似于C#代码契约.
在正常处理过程中出现意外情况/异常导致某些对象处于不一致状态的特定情况下,我们可以/应该采用什么机制来支持范围守卫将要投诉的事实当我们跳出这个功能?
这里有一些示例伪代码来说明我的观点:
struct IObjectValidator;
struct ObjectValidatorScopeGuard
{
ObjectValidatorScopeGuard(IObjectValidator * pObj)
: m_ptr(pObj)
{
Assert(!m_ptr || m_ptr->isValid());
}
~ObjectValidatorScopeGuard()
{
Assert(!m_ptr || m_ptr->isValid());
}
private:
IObjectValidtor * m_ptr;
};
int SomeComponent::CriticalMethod(const ThingA& in, ThingB& inout, ThingC * out)
{
ObjectValidatorScopeGuard sg1(static_cast<IObjectValidator *>(&in));
ObjectValidatorScopeGuard sg2(static_cast<IObjectValidator *>(&inout));
ObjectValidatorScopeGuard sg3(static_cast<IObjectValidator *>(out));
// create out
try
{
out = new ThingC();
out->mergeFrom(inout, out); // (1)
}
catch (const EverythingHasGoneHorriblyWrongException& ex)
{
// (2) out and inout not guaranteed valid here..
}
return 0;
} …Run Code Online (Sandbox Code Playgroud) 在设计零安全代码时,更好的方法是什么?
F#和Scala具有封装null检查的Options类型,但我们也有代码契约,findbugs等静态代码分析工具.
对我来说,静态分析看起来有点清晰,那么Option/Maybe的原因是什么?特别是,什么使它更好地防止NullPointerExceptions/NullReferenceExceptions?
如何指示方法永远不会返回null?目前这是我的代码.
第19行获得了一个Ensures未经验证的消息,即使CreateFunction假定结果不是什么.
1 <Pure()> Public Function CreateFunction(Of TArg1, TArg2, TResult)(ByVal body As Func(Of Expression, Expression, BinaryExpression)) As Func(Of TArg1, TArg2, TResult)
2 Contract.RequiresAlways(body IsNot Nothing)
3 Contract.Assume(Contract.Result(Of Func(Of TArg1, TArg2, TResult))() IsNot Nothing)
4
5 Dim arg1 = Expression.Parameter(GetType(Integer), "arg1")
6 Dim arg2 = Expression.Parameter(GetType(Integer), "arg2")
7
8
9 Dim temp = Expression.Lambda(body(arg1, arg2), arg1, arg2)
10 Contract.Assume(temp IsNot Nothing)
11 Return DirectCast(temp.Compile, Global.System.Func(Of TArg1, TArg2, TResult))
12 End Function
13
14 <Pure()> Public Function Add() As Func(Of T, T, …Run Code Online (Sandbox Code Playgroud) 我们正在构建业务应用程序而不是其他人使用的API,在这种情况下,我更喜欢在if/then/throw模型中使用我们的验证逻辑.有人告诉我,最好使用代码合同.我没有看到任何好处,有没有明显的好处,我没有看到?我看到使用代码契约的问题,因为它是静态方法调用,并且在编译阶段之后还会发生一些代码注入.谢谢
我与一位同事讨论了使用代码合同来执行先决条件检查.
假设我们有以下代码:
namespace Project
{
using System;
using System.Diagnostics.Contracts;
public class Thing
{
public string Foo { get; set; }
public int Bar { get; set; }
}
public class ThingsManipulator
{
public void AddThing(Thing thing)
{
Contract.Requires<ArgumentNullException>(thing != null);
// Do something
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果// Do something我正在访问thing.Foo和thing.Bar执行操作,我是否应该通过代码合同验证它们?
public void AddThing(Thing thing)
{
Contract.Requires<ArgumentNullException>(thing != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(thing.Foo));
Contract.Requires<ArgumentException>(thing.Bar > 0);
// Do something
}
Run Code Online (Sandbox Code Playgroud)
我的同事说只应检查整个参数(即我们应该只放置第一个合同),我认为方法应检查它们使用的是什么,无论它是整个参数还是其中一个属性(即我们应该全部三个合同).
请注意,我理解并同意,如果参数的属性应始终满足要求,则该要求应放在对象的不变检查中.
我所指的是通常有效的值,但对于特定方法无效(例如,在上面的示例中thing.Bar可能很乐意保留负值,但AddThing不喜欢它们).
我的同事说在这些情况下,方法签名应该显示它使用的所有项目而不是单个对象(例如AddThing(string …
几年前,有很多有关代码合同的信息。我没有时间去学习它,现在才发现这一次:)
但是当我尝试使用它时,我发现Visual Studio 2017不支持它,CC工具上次更新是在3年前...
那么,代码合同暂时关闭了吗?
C ++ 20围绕合同提供了一些令人惊叹的新功能-对于模板来说,这将使生活变得更好-可以将围绕类型或其他编译时要求的约束放入模板定义中,并由编译器进行适当的诊断。好极了!
但是,我非常担心在发生运行时先决条件冲突时无条件终止的努力。
https://en.cppreference.com/w/cpp/language/attributes/contract
可以使用两种违规继续模式之一来翻译程序:
关(如果未选择任何连续模式,则为默认值):违反处理程序的执行完成后,将调用std :: terminate; on:违反处理程序的执行完成后,将继续正常执行。鼓励实现不提供任何编程方式来查询,设置或修改构建级别或设置或修改违规处理程序。
我已经编写了广泛的面向用户的软件,该软件将所有异常捕获到一个核心执行循环中,在该循环中记录错误并通知用户有关失败的信息。
在许多情况下,用户最好尽可能地保存并退出,但在其他许多情况下,可以通过更改他们正在处理的设计/数据文件中的内容来解决错误。
这就是说,仅通过更改其设计(例如CAD设计),他们希望执行的操作即可成功。例如,代码执行时的公差可能过紧,从而无法根据该结果计算结果。更改容差后,只需重新运行该过程即可成功(不再违反基础代码中某个地方的违规前提条件)。
但是推动前提条件的努力简单地终止了,没有能力捕获这种错误并重试该操作吗?这听起来像是功能集的严重降级。诚然,在某些领域中确实需要这样做。快速失败,提早失败,并且对于先决条件或后置条件,问题出在编写代码的方式上,并且用户无法补救这种情况。
但是...这是一个很大的问题,但是...大多数软件都会针对运行时提供的未知数据集执行-声称所有软件都必须终止,并且无法期望用户纠正这种情况似乎很奇怪。
赫伯·萨特(Herb Sutter)在ACCU的讨论似乎与前提条件和后置条件违反仅仅是终止条件的观点紧密相关:
https://www.youtube.com/watch?v=os7cqJ5qlzo
我正在根据您的编码经验告诉您其他C ++专业人员在想什么?
我知道许多项目都不允许例外。如果您正在从事一个这样的项目,这是否意味着您编写代码以在发生无效输入时简单地终止?还是您使用错误状态回退到能够以某种方式继续的某些父代码点?
也许更重要的是-也许我误解了C ++ 20运行时合同的意图本质?
请保持这种文明的态度-如果您的建议是结束这种做法-也许您会友好地指向一个更合适的论坛进行讨论?
总的来说,我正在努力让我满意:
如何检查和处理违反先决条件的行为(使用最佳实践)?