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