C# 代码契约:如何验证其他程序集中定义的接口方法的参数?
我遇到了一个情况,我不知道该如何解决。 根据用户手册第3节,一个contractmethod,即<在重写方法/属性或接口实现中不允许使用 code>Require 或 Ensure
。契约方法应在根虚拟/抽象方法中声明,并且由于您无法在抽象方法中声明代码,因此必须使用 ContractClassAttribute
和 ContractClassForAttribute
。接口成员的契约方法(及其实现)也是如此。
但是如果我想使用一个不是我自己创建的界面怎么办?例如,IList
没有实现这些约定方法,但我也无法在其上设置 ContractClassAttribute
。我应该如何在 IList
的实现中进行参数验证?不允许使用以下解决方案:
T IList<T>.this[int i]
{
get
{
Contract.Requires(i >= 0);//not allowed
if (i < 0)
throw new ArgumentException();
Contract.EndContractBlock();//also not allowed
...
}
}
不带 EndContractBlock
的旧版 if-then-throw 语句是唯一的解决方案吗?
I have a situation I don't know how it's supposed to be solved.
According to the user manual section 3, a contractmethod, i.e. Require
or Ensure
, is not allowed in overriding methods/properties or interface implementations. The contract methods should be declared in the root virtual/abstract method and since you can't declare code in an abstract method, you have to work with the ContractClassAttribute
and ContractClassForAttribute
. The same goes for contractmethods for interfacemembers(and their implementations).
But what if I want to use an interface I haven't created myself? For example IList<T>
doesn't implement these contract methods, but I can't set the ContractClassAttribute
on it either. How should I do parametervalidation in for example the implementation of IList<T>.this[int]
? The following solutions aren't allowed:
T IList<T>.this[int i]
{
get
{
Contract.Requires(i >= 0);//not allowed
if (i < 0)
throw new ArgumentException();
Contract.EndContractBlock();//also not allowed
...
}
}
Are the legacy if-then-throw statements without EndContractBlock
the only solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,IList 已经指定了该前提条件。我只是尝试了一下以确保:“前提条件失败:索引 >= 0”。
此外,据我了解,后置条件是允许的,只有先决条件不允许。
如果您还想添加其他先决条件,我相信这可以回答您的问题:
http://social.msdn.microsoft .com/Forums/en/codecontracts/thread/af403bbc-ca4e-4546-8b7a-3fb3dba4bb4a
这基本上可以归结为这样一个事实:您不应该这样做,因为这会违背代码契约的目的。
First of all, IList<T> already specifies that precondition. I just tried it to be sure: "Precondition failed: index >= 0".
Furthermore, as I understand it, post conditions are allowed, only preconditions aren't.
If, you would still like to add other preconditions, I believe this answers your question:
http://social.msdn.microsoft.com/Forums/en/codecontracts/thread/af403bbc-ca4e-4546-8b7a-3fb3dba4bb4a
It basicly comes down to the fact that you are not meant to do so, as that would defy the purpose of code contracts.
不能添加前提条件的原因与不能这样做的原因相同:
它与(同/反)方差相关 - 方法参数是逆变的,这意味着您接受的类型必须“至少与自由主义”作为接口指定的类型。
添加更多先决条件会使类型更小/更严格,就像接受该类型的子类一样(如上面的示例)。*出于明显的原因,您不能这样做 - 一个实现了当传递正确的参数时,接口可能无法工作!如果你翻转了
Parent
&孩子
没关系。对于方法返回类型,情况正好相反:它们是协变的,这意味着您必须“至少与接口指定的类型一样小/严格”。这就是为什么您可以添加后置条件,因为您正在使类型“更小/更严格”。这与它起作用的原因相同:
*(这实际上提出了一个问题:您是否应该能够从实现类中删除前置条件。这将是一个有趣的功能。)
The reason you can't add preconditions is the same reason you can't do this:
It's related to (co-/contra-)variance — method parameters are contravariant, meaning the type you accept has to be "at least as big/liberal" as the type that the interface specifies.
Adding more pre-conditions is making the type smaller/stricter, in the same way that accepting a subclass of the type would be (like in the example above).* You can't do this for obvious reasons — a class which implements the interface might not work when passed the correct arguments! If you flipped
Parent
&Child
it would be ok.With method return types it's the other way around: they're covariant, meaning you have to be "at least as small/strict" as the type the interface specifies. This is why you can add post-conditions, because you're making the type "smaller/stricter". It's the same reason why this works:
* (This actually raises the question of whether you should be able to remove pre-conditions from implementing classes. This would be an interesting feature.)