4

クラスにプライベート静的読み取り専用フィールドがあります。

public class MyClass
{
    // ISSUE #1 -- requires unproven: path != null
    private static readonly DirectoryInfo MyDirectory =
        new DirectoryInfo(Settings.Default.MyDirectoryPath);

    protected virtual void SomeMethod()
    {
        if (MyDirectory.Exists)
        {
            // ISSUE #2 -- requires unproven: !string.IsNullOrEmpty(path)
            var catalog = new DirectoryCatalog(MyDirectory.FullName);
        }
    }
}

For issue #1 I used a null coalescing operator to default to some magic string and that fixed it, but I don't really like that solution. I was hoping there was a better solution.

For issue #2 the only thing I can think of is using a Contract.Assumes because if I attempt to use Contract.Requires(MyDirectory.Exists || !String.IsNullOrEmpty(MyDirectory.FullName)); it complains about visibility (private field used in a requires on a protected method).

4

4 に答える 4

1

現在のプロジェクトでコードコントラクトをしばらく使用した後、問題を修正するためにコードを書き直す必要があることがわかりました。ここには実際に2つのオプションがあります。

  1. プロジェクト設定に設定を追加して、特定の警告を無視するために適用する正しい属性を出力できます。これを行うには、プロジェクトファイル設定の[コードコントラクト]タブの[詳細]セクションにある[追加の静的チェッカーオプション]に[-outputwarnmasks]フラグを追加します。これにより、[ビルド出力]ウィンドウに情報が追加され、個々のケースを無視するために追加する正しい属性が提供されます。(Entity Frameworkを扱うときに非常に便利です)。
  2. 警告が表示されないように、コードを書き直して、適切なRequiresとEnsuresをコードに追加できます。

コードを書き直したい場合:問題#1を解決するには、Settingsクラスをラップし、コードで生成されていないプロパティとして新しいMyDirectoryPathを公開して、チェックを追加して空の文字列を返すことができるようにする必要があります。Contract.Ensures(Contract.Result<string>() != null)プロパティのゲッターの上部にを追加します。

問題#2を解決するには、適切なEnsuresとRequiresを追加するプライベート静的プロパティ内のクラスフィールドへのアクセスをラップする必要があります。

特に複雑なクエリで属性を追加する必要があるEntityFramework/ LINQを除いて、私は通常、可能な限りコードを書き直しました。

**免責事項**これらのタイプのアイテムを回避する他の方法に関する情報はあまりないため、これらは問題を解決するために私が見つけた方法にすぎません。

于 2012-06-19T12:28:15.413 に答える
1

問題 #1Settings.Default.MyDirectoryPathは、プロパティのコントラクトなしで Visual Studio によってコードが生成された結果です。この問題は null 文字列に限定されません。現在、多くの API には、aTimeSpanが負でないことを要求するコントラクトがありますが、API で直接設定を使用すると、コード コントラクトの警告が生成されます。

この問題を解決する方法は、コントラクトを持つメソッドで設定をラップすることです。例えば:

String GetMyDirectoryPath() {
  Contract.Ensures(Contract.Result<String>() != null);
  var myDirectoryPath = Settings.Default.MyDirectoryPath;
  Contract.Assume(myDirectoryPath != null);
  return myDirectoryPath;
}

が実際に設定の検証を実行する方法に注意してContract.Assumeください (外部構成ファイルによって制御されるため、コード コントラクトでは検証できません)。TimeSpan非負であると予想される であった場合は、代わりに独自の例外を使用Contract.Assumeして検証を実行するために使用するか、ContractExceptionまたは他の方法を使用できます。

この余分なレイヤーを追加するのはやや面倒ですが、設定はアプリケーションの外部で定義されるため、インタラクティブなユーザー入力を検証する必要があるのと同じように、ある時点で実行時に検証する必要があります。

問題#2は、おそらくDirectoryInfo契約が定義されていないためです。最も簡単な方法は、 を使用することContract.Assumeです。これにより、予想される動作であると信じていることについての声明が作成されますが、DirectoryInfoその考えが正しいことを確認するために実行時チェックが行われます (コードでチェックを保持している場合)。

var path = MyDirectory.FullName;
Contract.Assume(!string.IsNullOrEmpty(path));
var catalog = new DirectoryCatalog(path);
于 2012-06-19T12:55:01.090 に答える
0

&&さて、Issue#2については、使用したくないと思います||。しかし、それを超えて、おそらく問題#1の場合、静的コンストラクターにそれらのチェックを入れることができますか?Issue#2のもう1つのオプションは、ディレクトリをパラメータとして受け取るメソッドを用意することです。

private static readonly DirectoryInfo MyDirectory;

static MyClass()
{
    Contract.Requires(Settings.Default.MyDirectoryPath != null);
    MyDirectory = new DirectoryInfo(Settings.Default.MyDirectoryPath);
}

protected void SomeMethod()
{
    SomeOtherMethod(MyDirectory);
}

protected virtual void SomeOtherMethod(DirectoryInfo directory)
{
    Contract.Requires(directory.Exists && !String.IsNullOrEmpty(directory.FullName));

    var catalog = new DirectoryCatalog(directory.FullName);
}

私はAPIを使った経験があまりないContractので、これらすべてに夢中になっているかもしれません。:)

于 2012-06-19T12:28:36.663 に答える
0

Contract.Requires(MyDirectory.Exists || !String.IsNullOrEmpty(MyDirectory.FullName));

これをしないでください!いつでもMyDirectory.Exists変更でき、呼び出し元はそれを保証できません。ディレクトリが存在しない場合は、例外をスローするだけです。これが例外の目的です。

于 2012-06-26T03:29:00.100 に答える