我在 C# 4.0 中使用代码合同。我正在应用通常的静态方法链接来模拟可选参数(我知道 C# 4.0 支持可选参数,但我真的不想使用它们)。
问题是,如果我调用该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)));