你能把代码契约放在私有字段上吗?
本文关键字:字段 代码 契约 | 更新日期: 2023-09-27 18:11:44
为了简单起见,假设我有一个私有字段来缓存集合的计数:
private int _count;
我想确保计数永远不低于零。我可以在不变量中检查:
[ContractInvariantMethod]
private void invariant(){
Contract.Invariant(_count >= 0);
}
然而,这只会在退出公共方法时捕获错误-而不是在它发生时。该值可以通过更复杂的算法来赋值,因此获得它失败的确切时间是有价值的。
我可以用这样的属性来包装合同:
public int Count {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
return _count;
}
private set {
Contract.Requires(value >= 0);
_count = value;
}
}
但这并不能确保我不直接访问字段,而且在内部修改值时,它增加了通过属性的额外开销。因为setter是私有的,所以我也不能把契约贴在接口上。
是否有可能用合同注释字段,以确保在设置时检查它?
我认为从性能和稳定性两方面来说,使用属性是最好的方法。
public int Count {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
return _count;
}
private set {
Contract.Requires(value >= 0);
_count = value;
}
}
但是这并不能确保我不直接访问这个字段…
为真,但是作为代码作者的您可以确保该字段永远不会被直接访问。如果这样做风险太大(大型团队,缺乏纪律的程序员等),您可以将Count
属性移到具有更简单实现的基类中。
…它增加了在内部修改值时遍历属性的额外开销。
为真,您必须在性能和确保稳定性之间做出选择。如果您确实需要从性能时间中节省每一毫秒,请考虑使用不同的方法来获取和设置这个Count值,例如用公共GetCount()和/或SetCount()方法替换公共属性(不确定方法是否会产生相同的开销,我只是抛出一些想法)。
这似乎可以使用PostSharp的属性Required
:
[Required]
private int _count;
他们给出了下面的例子:
public class CustomerModel
{
[Required]
private string mFirstName = “Not filled in yet”;
public void SetFirstName(string firstName)
{
mFirstName = firstName;
}
}
和
在这个例子中,firstName在被分配给mFirstName之前将被Required契约验证。在一个字段上放置一个合约提供了一个额外的好处,不管它是从哪里设置的,都可以验证该字段。
值得注意的是,虽然这可以工作,但它没有利用微软的代码契约。