I am writing a (very small) framework for checking pre- and postconditions of methods. Entry points are (they could be easily be methods; that doesn’t matter):
public static class Ensures { public static Validation That { get { ... } } } public static class Requires { public static Validation That { get { ... } } }
Obviously, checking the postconditions may be expensive, and isn’t actually necessary, when the method isn’t buggy. So I want a method which works like this:
public static class Ensures { [ConditionalCallingCode('DEBUG')] public static Validation ThatDuringDebug { get { ... } } }
where ConditionalCallingCodeAttribute means that this method should only run when the calling code is compiled with the DEBUG symbol defined. Is this possible?
I want client code to look like this:
public class Foo { public void Bar() { ... // do some work Ensures.That // do these checks always .IsNotNull(result) .IsInRange(result, 0, 100); Ensures.WhileDebuggingThat // only do these checks in debug mode .IsPositive(ExpensiveCalculation(result)); return result; } }
Of course, I can simply not provide WhileDebuggingThat. Then the client code would look like this:
public class Foo { public void Bar() { ... // do some work Ensures.That // do these checks always .IsNotNull(result) .IsInRange(result, 0, 100); #ifdef DEBUG Ensures.That // only do these checks in debug mode .IsPositive(ExpensiveCalculation(result)); #endif return result; } }
This is the fallback plan if nothing else works out, but it breaks DRY really badly.
As I understand it, marking WhileDebuggingThat with [Conditional('DEBUG')] will emit (or not) this method depending on whether DEBUG is defined during the compilation of the library, not of the assemblies which reference this library. So I could do this and then write documentation telling the library users to link debug builds of their code with the debug build of the library, and release builds with release builds. This doesn’t strike me as the best solution.
Finally, I could tell the library users to define this class inside their projects:
using ValidationLibrary; public static class EnsuresWhileDebugging { [Conditional('DEBUG')] public static Validation That() { return Ensures.That; } }
This should work as well, as far as I see, but still requires breaking the DRY principle, if only slightly.
Any solution that is found here would be slower than the actual checks. Also, since it would not be build into the compiler like
ConditionalAttribute, the parameters would still be calculated. If the postconditions could be very complicated, such asYou might consider using icelava’s suggestion to reflect on the calling assembly to find if it is built in debug or release – but then you must use some sort of delegate to delay the calculation – to ensure that it is only done when needed. e.g.:
The IsPositive function should run the lambda and check its result, only after reflecting to find out if it should be calculated.