'How to emit compiler errors for unfinished features in Release Mode for .NET code?

Being inspired by this article I asked myself how can I emit compiler errors or , at least stop the build, if a feature is not implemented.

The only quick solution I came up with, is by creating a custom attribute:

    public class NoReleaseAttribute : System.Attribute
    {

        public NoReleaseAttribute()
        {
#if RELEASE
            .
#endif
        }
    }

The idea is to have a syntactic error somewhere, but only for Release. I used an attribute because the IDE will help me find quickly the references to the attribute, and thus all places that I marked as needed to be completed or fixed before going in production.

I don't like this solution because I want one to emit a compiler error in each place that needs attention, not a single global error elsewhere.

Perhaps there is a more fitted solution.



Solution 1:[1]

You may use #error directive in your code, it will cause an error at compile-time.

Example usage:

static void Main(string[] args)
{
    DoSomeStuff();
}

#error Needs to be implemented
static void DoSomeStuff(){
    //This needs some work
}

Solution 2:[2]

There are no more fitted solution. You can use for your goal:

a) ObsoleteAttribute (may not fit your goal)

b) throw NotImplementedException in every place that you need to:

#if RELEASE
    throw new NotImplementedException();
#endif

c) Wrap throwing NotImplementedException with attribute as you described us.

Basically it is unnecessary to add code that will not be used anywhere - Visual Studio even marking this code with 0 usages and it will not be included in CIL. So you have to question yourself - do i really need useless code exist in our project? It is better to track unreleased features in tracking systems like YouTrack or something, than to search them in your code.

Solution 3:[3]

I would suggest using a build step that checks the code for TODO-comments and generates warnings for them. A quick google suggest the Warn About TODOs extension might do just that, but it is not something I have used. You should also configure your build to fail on most warnings. A possible risk here is that people will just avoid using todo-comments, since they will fail the build.

But needing such a check suggest you do not have sufficient testing of your code. I find it a good practice to at least do some level of testing before committing any code, and just about any testing should reveal if entire components are not implemented. Reviewing your own code before committing is another practice that could be useful.

Automated unit testing can be a great way to deal with things like this. If you write unit tests for all your components the tests should find things like this, especially if you throw NotImplementedException in placeholders. This might require you to write your tests before the components, but there are certainly arguments for such a development approach.

The next line of defense should be code review. Even a quick review should find methods that are not implemented.

The final line of defense should be independent testing. If someone else tests the new features against the specification, any significant missing functionality should be found.

Solution 4:[4]

void createDonar(){

      donate d1;

The d1 object is declared in automatic scope in this function. This means that d1 gets destroyed when this function returns. It will be gone. It will be no more. It will cease to exist. It will become an ex-object. When you declare non-static variables and objects in a function that's what happens to them when the function returns, that's how C++ works.

blood_bank_database.push_back(&d1);

The same function then pushes a pointer to d into this std::vector, and then returns. So, what has been accomplished here? This is what was accomplished here, the end result: the vector gets filled up with pointers to destroyed objects, and all subsequent use of those pointers becomes undefined behavior.

The general name for this kind of a problem is called "pointless use of pointers". This is because nothing of value gets accomplished by using pointers, when none are needed. blood_bank_database can simply be a

vector<donate> blood_bank_database;

and the rest of the code adjusted accordingly. The end result will be much simpler, and less error-prone.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BugFreeDuck
Solution 2 RelativeLayouter
Solution 3 JonasH
Solution 4 Sam Varshavchik