【发布时间】:2011-02-14 19:01:54
【问题描述】:
我在 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)));
【问题讨论】:
-
相关/重复:stackoverflow.com/questions/2539497/… 如果您想消除开销,您可以在发布版本中生成合同参考程序集并启用调用站点检查 - 请参阅文档了解更多详细信息。
-
附带说明,File.Exists 对于合同条件来说是一个糟糕的选择,因为调用者不能静态地保证这个条件。这应该被记录为例外情况,但它不应该成为具有约束力的合同的一部分,因为它永远不能保证得到满足。
-
谢谢,你说得对。更好的断言是使用正则表达式或其他方式在语法上验证路径。
标签: c# c#-4.0 code-contracts