4

C# 4.0 で Code Contracts を使用しています。オプションのパラメーターをシミュレートするために、通常の静的メソッド チェーンを適用しています (C# 4.0 がオプションのパラメーターをサポートしていることは知っていますが、実際には使用したくありません)。

問題は、メソッドを呼び出すと、コントラクト要件が 2 回 (または、実装する連鎖オーバーロードの数) 実行されることです。これはInit(string , string[])、以下のサンプル ソース コードから明らかな効果です。これは、特に私が使用するような比較的高価な要件のために、高価になる可能性がありFile.Existsます。

public static void Init(string configurationPath, string[] mappingAssemblies)
{
    // The static contract checker 'makes' me put these here as well as
    // in the overload below.
    Contract.Requires<ArgumentNullException>(configurationPath != null, "configurationPath");
    Contract.Requires<ArgumentException>(configurationPath.Length > 0, "configurationPath is an empty string.");
    Contract.Requires<FileNotFoundException>(File.Exists(configurationPath), configurationPath);
    Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mappingAssemblies");
    Contract.Requires<FileNotFoundException>(Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n)));

    Init(configurationPath, mappingAssemblies, null);
}

public static void Init(string configurationPath, string[] mappingAssemblies, string optionalArgument)
{
    // This is the main implementation of Init and all calls to chained
    // overloads end up here.
    Contract.Requires<ArgumentNullException>(configurationPath != null, "configurationPath");
    Contract.Requires<ArgumentException>(configurationPath.Length > 0, "configurationPath is an empty string.");
    Contract.Requires<FileNotFoundException>(File.Exists(configurationPath), configurationPath);
    Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mappingAssemblies");
    Contract.Requires<FileNotFoundException>(Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n)));

    //...
}

ただし、そのメソッドから要件を削除すると、静的チェッカーはオーバーロードの要件が満たされInit(string, string[], string)ていないと不平を言います。静的チェッカーは、Init(string, string[], string)オーバーロードの要件が暗黙的にInit(string, string[])メソッドにも適用されることを理解していないと思います。コード IMO から完全に控除できるもの。

これは私が達成したい状況です:

public static void Init(string configurationPath, string[] mappingAssemblies)
{
    // I don't want to repeat the requirements here because they will always
    // be checked in the overload called here.
    Init(configurationPath, mappingAssemblies, null);
}

public static void Init(string configurationPath, string[] mappingAssemblies, string optionalArgument)
{
    // This is the main implementation of Init and all calls to chained
    // overloads end up here.
    Contract.Requires<ArgumentNullException>(configurationPath != null, "configurationPath");
    Contract.Requires<ArgumentException>(configurationPath.Length > 0, "configurationPath is an empty string.");
    Contract.Requires<FileNotFoundException>(File.Exists(configurationPath), configurationPath);
    Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mappingAssemblies");
    Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n));

    //...
}

Init(string, string[], string)だから、私の質問はこれです:暗黙的にInit(string, string[])自動的に適用される要件を持つ方法はありますか?

アップデート

メソッドを間違った方法で使用してForAllいました。次のように、要件内などで使用することを目的としています。

Contract.Requires<FileNotFoundException>(Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n)));
4

2 に答える 2

1

一般的な場合は無いと思います。

あなたの特定のケースでは、より高価な ForAll(File.Exists) を実際の実装メソッドに移動し、警告を受け取ることはできません:

        public static void Init(string configurationPath, string[] mappingAssemblies)
    {
        Contract.Requires<ArgumentNullException>(configurationPath != null, "configurationPath");
        Contract.Requires<ArgumentException>(configurationPath.Length > 0, "configurationPath is an empty string.");
        Contract.Requires<FileNotFoundException>(File.Exists(configurationPath), configurationPath);
        Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mappingAssemblies");
        Init(configurationPath, mappingAssemblies, null);
    }

    public static void Init(string configurationPath, string[] mappingAssemblies, string optionalArgument)
    {
        Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mappingAssemblies");
        Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n));
    }

編集 - 以前のレベルでそれを行うことを忘れて、メソッドを ContractVerification() 属性で装飾するだけです。これにより、警告は表示されず、7 つのチェック済みアサーションが表示され、すべての静的チェック オプションがオンになっています。

    [ContractVerification(false)]
    public static void Init(string configurationPath, string[] mappingAssemblies)
    {
        Init(configurationPath, mappingAssemblies, null);
    }

    public static void Init(string configurationPath, string[] mappingAssemblies, string optionalArgument)
    {

        Contract.Requires<ArgumentNullException>(mappingAssemblies != null, "mapping assemblies");
        Contract.Requires<ArgumentNullException>(configurationPath != null, "configurationpath");
        Contract.Requires<ArgumentException>(configurationPath.Length > 0, "configurationPath is an empty string");
        Contract.Requires<FileNotFoundException>(File.Exists(configurationPath));
        Contract.Requires<FileNotFoundException>(Contract.ForAll<string>(mappingAssemblies, (n) => File.Exists(n)));


        // ... 
    }
于 2010-05-02T17:30:45.923 に答える
0

コントラクトを使用しているので、C# 4.0 を使用していると思います。次に、代わりにオプションのパラメーターを使用して、コントラクトを置く場所を 1 つだけにすることができます。

于 2010-09-27T11:45:26.563 に答える