为什么我会收到由 C# 代码编写的格式错误的合同?
当我在下面编写此合同时,Visual Studio 显示错误。
错误 20 方法“....get_Page”中的合同部分格式错误
是否是 if
块有问题?
public int? Page
{
get
{
int? result = Contract.Result<int?>();
if (result != null)
Contract.Ensures(result >= 0);
return default(int?);
}
}
编辑:
Lasse V. Karisen 在评论中发表了:
怎么样:Contract.Ensures(result == null || result >= 0);
?
是的,Karisen,我之前已经尝试过并且可以编译。但问题仍然存在:使用合约时是否可以有 if
?
我遇到的另一个问题是无能为力的(主要考虑上面的示例),还涉及结果的使用:
public int IndexOf(T item)
{
Contract.Assert(item != null);
Contract.Assert((item as IEntity).ID > 0);
int result = Contract.Result<int>();
Contract.Ensures(result >= -1);
return default(int);
}
Visual Studio shows an error when I write this contract below.
Error 20 Malformed contract section in method '....get_Page'
Is the problem with the if
block?
public int? Page
{
get
{
int? result = Contract.Result<int?>();
if (result != null)
Contract.Ensures(result >= 0);
return default(int?);
}
}
EDIT:
Lasse V. Karisen has posted in comments:
How about: Contract.Ensures(result == null || result >= 0);
?
Yes Karisen, I've tried this before and it compiles. But the question remains: isn't it possible to have if
s when using contracts?
Another problem I'm having is clueless (mainly considering the example above works), involves the use of result also:
public int IndexOf(T item)
{
Contract.Assert(item != null);
Contract.Assert((item as IEntity).ID > 0);
int result = Contract.Result<int>();
Contract.Ensures(result >= -1);
return default(int);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
合同格式错误,因为所有合同条款必须出现在任何其他代码之前。
The contract is malformed because all contract clauses MUST appear before any other code.
您不需要 if 来进行布尔操作,而是使用暗示!
此外,在测试方法参数和其他先决条件时,您应该使用 Requires not assert。
You do not need an if, to do boolian manipulation instead use implies!
Also you should use Requires not assert when testing method arguments, and other preconditions.
只是有一个猜测。也许应该是Contract.Ensures(result.Value >= 0)?
Just having a guess. Perhaps it should be
Contract.Ensures(result.Value >= 0)
?所有 Ensures 和 Requires 调用必须位于方法或属性主体中的所有其他语句之前,这包括像您正在使用的有助于可读性的简单赋值。
正确的语法
这是非常难看,比正常的
if (x || y) throw new ArgumentOutOfRangeException()
难看得多。特殊属性
有一种迂回的方法可以解决这个问题。
ContractAbbreviatorAttribute
和ContractArgumentValidatorAttribute
是 ccrewrite 可以理解的特殊属性,它们可以让您的生活更轻松。 (有关详细信息,请参阅系统.Diagnostics.Contracts
MSDN 上的命名空间文档或代码合同 手动。)如果使用 .NET 4 或更早版本:
这些属性位于 .NET 4.5 开始的框架中,但对于之前的版本,您可以从 Code Contracts 安装目录中获取它们的源文件。 (
C:\Program Files (x86)\Microsoft\Contracts\Languages\
) 在该文件夹中有CSharp
和VisualBasic
子文件夹,它们具有 < code>ContractExtensions.cs(或 .vb)包含所需代码的文件。ContractAbbreviatorAttribute
此属性可以有效地让您创建合同宏。有了它,您的页面属性可以像这样编写:
EnsuresNullOrPositive
也可以保存在静态类中并在您的项目中重复使用,或者公开并放置在实用程序库中。您还可以使其更加通用,如下一个示例。对于我自己的实用程序库,我有一个名为
Requires
的静态类和一个名为Ensures
的静态类,每个类都有许多用ContractAbbreviator
修饰的静态方法。以下是一些示例:可以像这样使用:
ContractArgumentValidatorAttribute
我在教程之外没有使用过这个,但基本上它可以让您在单个调用中编写多个
if (test) throw new ArgumentException()
调用,其行为类似于对Contract 的调用.需要
。由于它只处理参数验证,因此对您的后置条件示例没有帮助。All Ensures and Requires calls must be before all other statements in a method or property body, this includes simple assignments like you're using that help readability.
Proper syntax
This is very ugly, much uglier than normal
if (x || y) throw new ArgumentOutOfRangeException()
.Special Attributes
There is a somewhat roundabout way of getting around this.
ContractAbbreviatorAttribute
andContractArgumentValidatorAttribute
are special attributes that theccrewrite
understands which make your life easier. (For lots of details see theSystem.Diagnostics.Contracts
namespace documentation on MSDN or the Code Contracts manual.)If using .NET 4 or older:
These attributes are in the framework starting .NET 4.5, but for prior versions you can get a source file for them from the directory Code Contracts installs to. (
C:\Program Files (x86)\Microsoft\Contracts\Languages\
) In that folder areCSharp
andVisualBasic
subfolders that have aContractExtensions.cs
(or .vb) file containing the required code.ContractAbbreviatorAttribute
This attribute effectively lets you create contract macros. With it, your page property could be written like this:
EnsuresNullOrPositive
could also be kept in a static class and reused across your project, or made public and placed in a utility library. You could also make it more general like the next example.For my own utility library, I have a static class named
Requires
and a static class namedEnsures
, each with many static methods decorated withContractAbbreviator
. Here are some examples:These can be used like this:
ContractArgumentValidatorAttribute
I haven't used this one outside of tutorials, but basically it lets you write package several
if (test) throw new ArgumentException()
calls in a single call that behaves like a call toContract.Requires
. Since it only deals with argument validation, it wouldn't help with your post-condition example.合约上有条件编译标志。
在发布更多代码时
,
您现在看到问题了吗?
Contract have conditional compilation flag on them.
In release more you code
becomes
do you see the problem now?