我在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)));
答案 0 :(得分: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)));
// ...
}
答案 1 :(得分:0)
由于您使用的是Contracts,我假设您使用的是C#4.0。然后你可以使用可选参数,只有一个地方来签合同。