代码合约最佳实践
我有几个关于代码契约及其使用最佳实践的问题。假设我们有一个类,具有多个属性(例如见下文):
class Class1
{
// Fields
private string _property1; //Required for usage
private List<object> _property2; //Not required for usage
// Properties
public string Property1
{
get
{
return this._property1;
}
set
{
Contract.Requires(value != null);
this._property1 = value;
}
}
public List<object> Property2
{
get
{
return this._property2;
}
set
{
Contract.Requires(value != null);
this._property2 = value;
}
}
public Class1(string property1, List<object> property2)
{
Contract.Requires(property1 != null);
Contract.Requires(property2 != null);
this.Property1 = property1;
this.Property2 = property2;
}
public Class1(string property1)
: this(property1, new List<object>())
{ }
}
关于我想要实现的目标的一些解释:
(a)property1 是必填字段。 property2 对于对象的正常使用来说并不是明确需要的。
我有以下问题:
我是否应该考虑财产合同2;因为 property2 不是必填字段,所以它应该有合同吗?在 property2 上放置契约是否表明该对象的正常使用实际上需要它;
尽管 property2 没有明确要求,但它不可能为空,因此是在 setter 处定义的契约。在 property2 上定义契约不会减少调用代码中的 null 检查吗?这应该会减少 bug 并提高代码的可维护性 - 这个假设正确吗?
如果是正确的,我如何确保调用代码时property2永远不会为空?我是否使用 Contract.Invariant(property2 != null);或Contract.Ensures(property2 != null)在构造函数中,或Contract.Ensures(property2 != null)在Init()中,或Contract.Ensures(property != null)在setter中? (即,如果使用 Contract.Ensures(property2 != null),它放在哪里)?
如果问题看起来很简单,我很抱歉。我只是在寻找对此事的想法,以及你们认为的最佳实践。
I have several questions regarding code contracts, and the best practices for their usage. Lets say we have a class, with several properties (see below for example):
class Class1
{
// Fields
private string _property1; //Required for usage
private List<object> _property2; //Not required for usage
// Properties
public string Property1
{
get
{
return this._property1;
}
set
{
Contract.Requires(value != null);
this._property1 = value;
}
}
public List<object> Property2
{
get
{
return this._property2;
}
set
{
Contract.Requires(value != null);
this._property2 = value;
}
}
public Class1(string property1, List<object> property2)
{
Contract.Requires(property1 != null);
Contract.Requires(property2 != null);
this.Property1 = property1;
this.Property2 = property2;
}
public Class1(string property1)
: this(property1, new List<object>())
{ }
}
Some explanation about what I want to achieve:
(a) property1 is a required field. property2 is not explicitly required for normal usage of the object.
I have the following questions:
Should I even bother with the contracts for property2; because property2 is not a required field, should it have a contract at all. Does placing a contract on property2 indicate that it is in fact required for normal usage of the object;
Even though property2 is not explicitly required, there is no possible reason for it to be null, thus the defined contract at the setter. Wouldn't defining the contract on property2 reduce the null checks in calling code? This should reduce bugs and improve maintainability of the code - is this assumption correct?
If it is right, how do I ensure to calling code that property2 will never be null? Do I use Contract.Invariant(property2 != null); or Contract.Ensures(property2 != null) in the constructor, or Contract.Ensures(property2 != null) in the Init(), or Contract.Ensures(property != null) in the setter? (i.e. if using Contract.Ensures(property2 != null), where is it placed)?
My apologies if the questions seem simple. I am just looking for thoughts on the matter, and what you folks consider best practice.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这就是我对契约的建议:
属性有其公共行为契约,并且当您向 Class1 添加逻辑时,不变量将捕获您稍后可能引入的任何错误,这些错误可能会修改字段值,从而违反公共契约。或者,如果可以将字段设置为只读(并且删除设置器),则不需要不变量。
This is what I would recommend as far as Contracts:
The properties have their public behavioral contracts and the Invariants will catch any errors you might introduce later as you add logic to Class1 that could modify the field values and thus violate the public contracts. Alternately, if the fields can be made readonly (and the setters removed), you don't need the invariants.
我认为这里有很多个人偏好,但我的 2 美分......
1)我会,并且可能会试图调整构造函数以将 property2 作为可选参数:
2)参见 3
3)在我之前很高兴减少调用代码中的空检查,我个人更喜欢
在 getter 上看到 a - 我已经看到 VS11 CTP 在定义的工具提示中显示了契约,因此能够看到这一点,我就知道我不需要查看对于空值。我会将
Requires
保留在设置器上。I think there's a lot of personal preference in here, but my 2 cents...
1) I would, and would possibly be tempted to adjust the constructors to have property2 as an optional argument:
2) See 3
3) Before I'd be happy to reduce null checks in calling code, I would personally prefer to see a
on the getter - I've seen VS11 CTP shows contracts in the tooltips for definitions so being able to see this I would then know I don't need to check for nulls. I would keep the
Requires
on the setter.通常,当对象中有一个列表时,您将让该对象负责创建。因此,如果消费者希望添加到列表中,他们必须首先获取它。根据此类的使用情况,这可能是更好的路线。
Often when you have a List in an object you will have the object take care of the creation. So if a consumer wishes to add to a list they must first get it. Depending on the usage of this class this might be the better route.
1/2:如果您想要强制执行这种行为,那么在 property2 上签订合同是合适的,即它不应该为 null,并且肯定会减少对 null 检查的需要以及围绕 null 的潜在错误。
3:为了回答这个问题,我重写了您的类,如下所示
当您的类中有自动实现的属性时,您可以使用Contract.Invariant()。这使得您的财产中的显式合同变得多余,因此现在不需要以下代码。
这将照顾到财产保护。为了完全确保该属性永远不会为 null,您将在构造函数中添加 Contract.Requires(property1 != null)。
我知道这个答案迟了三年,但可能对你有用!
来源:http://research.microsoft.com/en-us/projects /contracts/userdoc.pdf
1/2: Having a contract on property2 is appropriate if that is the behaviour you want to enforce i.e. It should not be null, and will certainly reduce the need for null checks and potential bugs around nulls.
3: To answer this question I have rewritten your class as follows
When you have auto implemented properties in your class you can use
Contract.Invariant()
. This makes explicit contracts in your property redundant so there is no need for the following code now.That will take care of the property protection. To fully ensure that the property will never be null you will then add a Contract.Requires(property1 != null) in the constructor.
I know this answer is 3 years late but it may be of some use to you!
Source: http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf