How do I imply code contracts of chained methods to avoid superfluous checks while chaining?
Posted
by Sandor Drieënhuizen
on Stack Overflow
See other posts from Stack Overflow
or by Sandor Drieënhuizen
Published on 2010-05-02T16:11:46Z
Indexed on
2010/05/02
16:17 UTC
Read the original article
Hit count: 406
I'm using Code Contracts in C# 4.0. I'm applying the usual static method chaining to simulate optional parameters (I know C# 4.0 supports optional parameters but I really don't want to use them).
The thing is that my contract requirements are executed twice (or possibly the number of chained overloads I'd implement) if I call the Init(string , string[])
method -- an obvious effect from the sample source code below. This can be expensive, especially due to relatively expensive requirements like the File.Exists
I use.
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.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.ForAll<string>(mappingAssemblies, (n) => File.Exists(n));
//...
}
If however, I remove the requirements from that method, the static checker complains that the requirements of the Init(string, string[], string)
overload are not met. I reckon that the static checker doesn't understand that there requirements of the Init(string, string[], string)
overload implicitly apply to the Init(string, string[])
method as well; something that would be perfectly deductable from the code IMO.
This is the situation I would like to achieve:
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));
//...
}
So, my question is this: is there a way to have the requirements of Init(string, string[], string)
implicitly apply to Init(string, string[])
automatically?
© Stack Overflow or respective owner