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

C# 你能把代码契约放在私有字段上吗?,c#,field,code-contracts,C#,Field,Code Contracts,为了简单起见,假设我有一个专用字段,用于缓存我的集合计数: private int _count; 我想确保计数永远不低于零。我可以在不变量中检查这一点: [ContractInvariantMethod] private void invariant(){ Contract.Invariant(_count >= 0); } 然而,这只会在退出公共方法时发现错误,而不是在它发生时。这个值可以通过一个更复杂的算法来分配,因此获得它失败的确切时间是很有价值的 我可以将合同包装在这

为了简单起见,假设我有一个专用字段,用于缓存我的集合计数:

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;
    }
}
公共整数计数{
得到{
Contract.Result(Contract.Result()>=0);
返回计数;
}
专用设备{
合同要求(值>=0);
_计数=数值;
}
}
但这并不能确保我不直接访问该字段,而且在内部更改值时会增加遍历属性的额外开销。因为setter是私有的,所以我也不能将契约粘贴在接口上


是否可以使用合同对字段进行注释,以确保在设置字段时对其进行检查?

我认为使用属性是性能和稳定性方面的最佳方法

public int Count {
    get {
        Contract.Ensures(Contract.Result<int>() >= 0);
        return _count;
    }
    private set {
        Contract.Requires(value >= 0);
        _count = value;
    }
}
公共整数计数{
得到{
Contract.Result(Contract.Result()>=0);
返回计数;
}
专用设备{
合同要求(值>=0);
_计数=数值;
}
}
但这并不能确保我不直接访问字段

是的,但是作为代码作者,您可以确保永远不会直接访问该字段。如果风险太大(大型团队、无纪律的程序员等),可以将
Count
属性移动到具有更简单实现的基类

…它增加了在内部更改值时遍历属性的额外开销

是的,您必须在性能和确保稳定性之间做出决定。如果你真的需要从你的执行时间中去掉所有可能的毫秒,那么考虑一个获取和设置这个计数值的不同方法,比如用公共GETCONTUTE()和/或SETCONTUTE()方法替换公共属性(不确定如果方法导致相同的开销有属性,我只是抛出一些想法)。.

这似乎是:

他们举了以下例子:

public class CustomerModel
{
    [Required]
    private string mFirstName = “Not filled in yet”;

    public void SetFirstName(string firstName)
    {
        mFirstName = firstName;
    }
}

在本例中,firstName将在分配给mFirstName之前由所需的合同进行验证。将合同放置在字段上提供了验证字段的附加好处,而不管字段是从何处设置的


值得注意的是,尽管这是可行的,但它没有利用微软的代码契约。

在内部更改值时的“开销”?您非常关心微小的性能差异,而且从未检查属性访问是否是内联的检查反汇编-像这样的简单属性几乎总是内联的。我在使用属性而不是直接使用字段方面经历了很大的不同。缓存的计数值可能并非如此,但更频繁写入的值在隐藏在属性后面时肯定会显示负面影响。为了能够将注意力集中在合同的实际问题上,我将这个例子保持简单——我真正的问题不涉及计数变量。它仍然不会改变您可以直接访问价值的事实,从而避免了合同!在没有附加调试器的情况下,发布版本有很大的不同吗?我对此表示怀疑。如果附加了调试器,当然会阻止内联。即使这样,开销也是很小的,因此它只会在高吞吐量场景中给您带来麻烦——在这种情况下,您只需以维护成本为代价优化高性能(即“每个写入此字段的人都必须使用正确的先决条件”)。你不能既吃了蛋糕又吃了蛋糕——合同一定在什么地方。您是否仅将契约用于静态分析?至于隐藏字段,实际上只有两个选项—要么将其隐藏在父类中(使属性setter
受保护),要么将其隐藏在仅公开这些属性并保持字段私有的
结构中。
public class CustomerModel
{
    [Required]
    private string mFirstName = “Not filled in yet”;

    public void SetFirstName(string firstName)
    {
        mFirstName = firstName;
    }
}