Reputation: 3266
Due to requirements changing back and forth, we have some if/else blocks using consts in our code, for exampe:
const bool DisplayAverageValues = true;
if(DisplayAverageValue)
{
// Do this
}
else
{
// Do that
}
Since the requirements might change again, we don't want to remove the currently unused code - it might be needed next week. We also don't want to comment out the unused code, since we want it to be part of any refactoring. It should be ready for compilation at any time by just changing the boolean value.
The problem is that we get warnings for unreachable code, so I was thinking about replacing the standard if/else-block with the preprocessor #if/#else.
#define DisplayAverageValues
#if DisplayAverageValue
// Do this
#else
// Do that
#endif
The problem I'm facing now is that a preprocessor symbol can't be set to false, it can only be defined or undefined. It would be a lot more obvious to change from:
#define DisplayAverageValues true
to
#define DisplayAverageValues false
instead of
#undef DisplayAverageValues
or
//#define DisplayAverageValues
(which might cause trouble if the same symbol name has been used elsewhere).
Is there a better way?
Upvotes: 3
Views: 171
Reputation: 2016
Processor directives seems to be not designed for such cases. From SOLID point of view you should do the following:
1) Create some interface:
public interface IDoingSomething {
void Do();
}
2) Create 2 implementations of this interface:
public class DoingThis : IDoingSomething {
public void Do() {
// Do this
}
}
public class DoingThat : IDoingSomething {
public void Do() {
// Do that
}
}
3) Somewhere at the application starting point read the config and make decision of which implementation to use:
IDoingSomething doerSomething;
if(DisplayAverageValue) {
doerSomething = new DoingThis();
} else {
doerSomething = new DoingThat();
}
4) Now use you interface object in code to do something:
doerSomething.Do();
This is kind of Strategy pattern that allows you to have multiple implementations, swith between them in just one place and do not require any code change except classes with concrete interface implementation. This is good for code maintenance, scalability etc.
Upvotes: 1
Reputation: 3266
There were some good suggestions in the comments and in the answer by Tigran, but for now I will stay with a simple solution that is still easy to understand. By dropping the symbol name, there is no doubt in how to change the code if needed:
#if true
// Display average values
...
#else
// Do not display average values
...
#endif
Upvotes: 0
Reputation: 62276
Preprocessor dirrectives are good in case when you have presice slices in your code architecture, when one code has to be compilable and not intersecting with other. In your case, it much seems that you face different options, that somehow also may intersect in requirements along code execution flow.
In my opinion, the best way to manage this is define a Options
, RuntimeConfigurations
, or whatever else, class that holds all properties which would impact your application runtime behavior, and pass the instance (may be also a Singletone
) of that class along the parts of your application that has to take in consideration different execution options.
Another option as Daniel said, is exracting that code into different modules, plugins if you wish, and load them dynamically. But it may or may not be possible to implement, and by the way, you will need to spend non irrelevant amount of time, generaly, to achieve this level of flexibility, if it wasn't considered before in your architecture.
Upvotes: 2