2011-12-05 28 views
7

コード契約やその使用に関するベストプラクティスに関していくつか質問があります。コード契約のベストプラクティス

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)のプロパティ1は必須項目です、我々はいくつかのプロパティ(例えば以下を参照)で、クラスを考えてみましょう。 property2は、オブジェクトの通常の使用に明示的には必要ありません。

私は、次の質問がある:

  1. 私もproperty2の契約を気にすべきです。 property2は必須フィールドではないため、契約を結ぶ必要があります。 property2に契約を置くことは、オブジェクトの通常の使用に実際に必要であることを示します。

  2. property2が明示的に必要ではないにもかかわらず、それがnullである可能性はないので、定義されたコントラクトはセッターである。 property2の契約を定義しないと、呼び出しコードのヌルチェックを減らすことはできますか?これはバグを減らし、コードの保守性を向上させるはずです - この前提は正しいですか?

  3. 正しい場合は、property2が決してnullにならないようにするには、どうすればコードを呼び出すことができますか? Contract.Invariant(property2!= null)を使用しますか?コンストラクタ内のContract.Ensures(property2!= null)、またはInit()のContract.Ensures(property2!= null)、またはsetter内のContract.Ensures(property!= null)? (つまり、Contract.Ensures(property2!= null)を使用している場合は、どこに配置されていますか?)

質問が簡単なようであれば謝罪します。私はその問題に関する考えを探しているだけで、皆さんがベストプラクティスと考えるものを探しています。

+0

私はあなたが記載されている理由のために財産上の2契約に同意します。 –

答えて

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); 
     } 
    } 

性質は彼らの公共の行動の契約を持っていて、それをClass1のためのロジックを追加すると、不変条件が後であなたが紹介する可能性のあるエラーをキャッチしますフィールド値を修正し、公的契約に違反する可能性があります。また、フィールドを読み込み専用にすることができ(そしてセッターが削除された)、不変量は必要ありません。

+0

私はセッターのCEに同意するでしょう。コード契約サンプルの文書を読んだ後で、これは開発者が意図した方法であるように見えます。後で違反をキャッチするインバリアントにはい。ありがとう、私の理解を助けてくれました。 –

2

私は個人的な好みの多くはここにあると思うが、私の2セント...

1)私が考え、そしておそらくオプションの引数としてproperty2を持つようにコンストラクタを調整するために誘惑されるだろう。

Class1(string property1, List<object> property2 = new List<object>())  
{  
    Contract.Requires(property1 != null);  
    Contract.Requires(property2 != null);  

    this.Property1 = property1;  
    this.Property2 = property2;  
} 

2)私は個人的に

Contract.Ensures(property2 != null) 
を参照してくださいすることを好む3

3)私はコードを呼び出すにはnullチェックを軽減させていただきます前に、参照してください。

getter - 私はVS11を見ました。CTPは定義のツールチップに契約を示していますので、これを見ることができるので、nullをチェックする必要はありません。私はセッターにRequiresを保持します。

+0

優れています。ありがとう –

1

多くの場合、オブジェクトにリストがあると、そのオブジェクトにオブジェクトが作成されます。したがって、消費者がリストに追加したい場合は、まずそれを取得する必要があります。このクラスの使用状況に応じて、これはより良いルートかもしれません。

class Class1 
{ 
    // Fields 
    private string _property1;  //Required for usage 
    private List<object> _property2 = new List<object>(); //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; 
     } 
     //We don't have a setter. 
    } 

    public Class1(string property1) 
    { 
     Contract.Requires(property1 != null); 

     this.Property1 = property1; 
    } 
} 
+0

リストアスペクトに関する情報をありがとう。私の心配の1つだったので、それを私の不必要な財産として含めました。私は主に、それがリストであるかどうかに関係なく、「必須でない」プロパティの契約をどのように処理するかについてのアドバイスを探していました。コメントはありますか? –

+0

「コレクション」でない場合、私はスマッジのアドバイスに従います。コンストラクターにデフォルトを作成し、それがヌルでないことを要求することによって、コンシューマーにAPIを提供する場合、非ヌル値を提供する必要があることをAPIに通知します。 –

1

1/2:これは、強制的に実行する動作、つまりnullであってはならず、ヌルを回避する必要性とnullの可能性のあるバグを確実に減らすために、property2の契約を結ぶことが適切です。

3:あなたはContract.Invariant()を使用することができ、あなたのクラスの自動実装プロパティを持っている場合は

class Class1 
{ 
    //Properties 
    public string Property1 { get; set; } 
    public List<object> Property2 { get; set; } 

    public Class1(string property1, List<object> property2) 
    { 
     Contract.Requires(property1 != null); 
     Contract.Requires(property2 != null); 

     Property1 = property1; 
     Property2 = property2; 
    } 

    public Class1(string property1) 
     : this(property1, new List<object>()) 
    { 
     Contract.Requires(property1 != null); 
    } 

    [ContractInvariantMethod] 
    private void ObjectInvariant() 
    { 
     Contract.Invariant(Property1 != null); 
     Contract.Invariant(Property2 != null); 
    } 
} 

を次のように私はあなたのクラスを書き換えてきたこの疑問に答えるために。これはあなたの財産の明示的な契約を冗長にするので、次のコードは今必要ありません。

public string Property1 
{ 
    get 
    { 
     Contract.Ensures(Contract.Result<string>() != null); 
     return this._property1; 
    }    
    set 
    { 
     Contract.Requires(value != null); 
     this._property1 = value; 
    } 
} 

これは財産保護を担当します。プロパティがnullにならないようにするには、コンストラクタにContract.Requires(property1!= null)を追加します。

私はこの回答が3年遅れていることを知っていますが、それはあなたの役に立つかもしれません!

出典:http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf

関連する問題