21

次のシナリオがあります。

public interface ISomething
{
    void DoStuff();
    //...
}

public class Something : ISomething
{
    private readonly ISomethingElse _somethingElse;
    //...

    public Something (ISomethingElse somethingElse)
    {
         Contract.Requires(somethingElse != null);
        _somethingElse = somethingElse;
    }

    public void DoStuff()
    {
        // *1* Please look at explanation / question below
        _somethingElse.DoThings();
    }
 }

1行目で静的チェッカーをオンにすると、それが null である可能性があるという警告が表示されます。_somethingElseコントラクトを追加すると、エラーが発生します。

[Type] インターフェイス メソッド {Interface.Method} を実装しているため、require を追加できません

ここで何をするのが最善ですか?私が見るオプションは次のとおりです

  1. 少し極端に見えますが、ガード条項
  2. aContract.Assume
  3. 私が考えもしなかった隠された第3の選択肢

readonlyこのフィールドは、コンストラクターで値を設定した後は変更できないことに注意してください。したがって、コード コントラクトからの警告は少し無関係に思えます。

4

1 に答える 1

19

説明

セクション3:ユーザーマニュアルのコントラクト継承では、すべての前提条件を継承/実装チェーンのルートメソッドで定義する必要があると述べています。

oクライアントが前提条件を満たしていることを確認し、静的型がである変数を持っている場合、Tクライアントはを呼び出したときに前提条件違反を取得するべきではありませんo.M。ランタイム値のoタイプが。であっても、これはtrueである必要がありますU。したがって、このメソッドU.Mは、の前提条件よりも強い前提条件を追加することはできませんT.M

より弱い前提条件を許可することはできますが、そうすることの複雑さが利点を上回ることがわかりました。前提条件を弱めることが役立つ説得力のある例は見たことがありません。したがって、サブタイプに前提条件を追加することはまったく許可されていません。

結果として、メソッドの前提条件は、継承/実装チェーンのルートメソッド、つまり最初の仮想または抽象メソッド宣言、またはインターフェイスメソッド自体で宣言する必要があります。

解決

あなたの状況では、最善の行動は、_somethingElseフィールドが決してnullにならないことを示す不変条件を設定することです。

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

readonlyフィールドはコンストラクターでマークされて初期化されるため、これはもちろん常に当てはまります。ただし、静的チェッカーはそれ自体ではこれを推測できないため、その不変条件を介して明示的に伝える必要があります。

オプションでコンストラクターに事後条件を追加できますContract.Ensures(_somethingElse != null);が、静的チェッカーはそれを必要としません。

于 2010-08-05T12:50:54.850 に答える