代码合同最佳实践

Red*_*con 7 c# contracts

关于代码合同以及使用它们的最佳实践,我有几个问题.假设我们有一个类,有几个属性(例如见下文):

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>())
    { }
}
Run Code Online (Sandbox Code Playgroud)

关于我想要实现的目标的一些解释:

(a)property1是必填字段.对象的正常使用不明确要求property2.

我有以下问题:

  1. 我是否应该为财产2的合同烦恼; 因为property2不是必填字段,所以它应该有合同.在property2上签订合同是否表明它实际上是正常使用对象所必需的;

  2. 即使没有明确要求property2,也没有可能的原因使它为null,因此在setter处定义了契约.不定义property2上的契约会减少调用代码中的空值检查吗?这应该可以减少错误并提高代码的可维护性 - 这个假设是否正确?

  3. 如果它是正确的,我如何确保调用property2永远不会为null的代码?我是否使用Contract.Invariant(property2!= null); 或者在构造函数中的Contract.Ensures(property2!= null),或者在setter中的Init()或Contract.Ensures(property!= null)中的Contract.Ensures(property2!= null)?(即如果使用Contract.Ensures(property2!= null),它放在哪里)?

如果问题看似简单,我道歉.我只是在寻找关于此事的想法,以及你们认为最好的做法.

Dan*_*ant 3

就合同而言,这是我的建议:

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

这些属性具有其公共行为契约,并且当您向 Class1 添加逻辑时,不变量将捕获您以后可能引入的任何错误,这些错误可能会修改字段值,从而违反公共契约。或者,如果可以将字段设置为只读(并且删除设置器),则不需要不变量。