C# · 12月 22, 2021

c# – 代码合同最佳实践

关于代码合同以及使用它们的最佳实践,我有几个问题.假设我们有一个类,有几个属性(例如见下文): 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,也没有可能的原因使它为null,因此在setter处定义了合约.不会在property2上定义合约减少调用代码中的空值检查吗?这应该可以减少错误并提高代码的可维护性 – 这个假设是否正确?
>如果它是正确的,我如何确保调用property2永远不会为null的代码?我是否使用Contract.Invariant(property2!= null);或者在构造函数中的Contract.Ensures(property2!= null),或者在setter中的Init()或Contract.Ensures(property!= null)中的Contract.Ensures(property2!= null)? (即如果使用Contract.Ensures(property2!= null),它放在哪里)?

如果问题看似简单,我表示歉意.我只是在寻找关于此事的想法,以及你们所考虑的最佳实践.

解决方法 这就是我建议的合同: class Class1 { // Fields private string _property1; //required for usage private List<object> _property2; //Not required for usage // Properties public string Property1 { get { Contract.Ensures(Contract.Result<string>() != null); return this._property1; } set { Contract.Requires(value != null); this._property1 = value; } } public List<object> Property2 { get { Contract.Ensures(Contract.Result<List<object>>() != null); 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>()) { Contract.Requires(property1 != null); } [ContractInvariantMethod] private void ContractInvariants() { Contract.Invariant(_property1 != null); Contract.Invariant(_property2 != null); } }

这些属性具有公共行为合同,并且Invariants将捕获您稍后可能引入的任何错误,因为您向Class1添加了可能修改字段值并因此违反公共合同的逻辑.或者,如果字段可以只读(并且删除了setter),则不需要不变量.