你能把代码契约放在私有字段上吗?

本文关键字:字段 代码 契约 | 更新日期: 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契约验证。在一个字段上放置一个合约提供了一个额外的好处,不管它是从哪里设置的,都可以验证该字段。

值得注意的是,虽然这可以工作,但它没有利用微软的代码契约。