In the previous post, we examined how spelling related FxCop messages could be handled by using a custom dictionary file. In this post, we’ll look at the techniques for dealing with other messages that we do not intend to change code to resolve.
In working with some code recently, I was working my way through the FxCop messages as always, when I came upon an AvoidNamespacesWithFewTypes message. The Info property for the message reads: “A namespace should generally have more than five types.” And the Resolution: “Consider merging the types defined in ‘OvidEast.Xna.Framework’ with another namespace.”
Now the code I’m writing is meant to mirror the XNA namespaces as much as possible. Thus, in this case the code in OvidEast.Xna.Framework both corresponds with Microsoft.Xna.Framework, it is also shared amongst the sub-namespaces. In other words, while in general I agree that namespaces should probably have more than just a few types in them, in this case, we believe our design is a valid exception to the rule. We can suppress the message.
There are a variety of different ways to suppress a message. The first and simplest way is to simply turn off checking for the rule that generated the message. Clicking on the “Rules” tab, Expanding the “Design Rules” tree node, and deselecting the “Avoid namespaces with a few types” check box will do the trick. In some cases, this is the best way to go, especially if the rule in question directly conflicts with a design guideline of your own. Information about which rules are enabled and disabled may be saved into the FxCop project file.
The second method is to exclude the message itself in the FxCop project file. The project file will always contain a list of all of the messages from the last run, and you can exclude a message from future runs by right clicking the message, selecting Exclude, and saving the project. In later runs, the message will appear in the “Excluded In Project” tab in the GUI.
The third method is to add an annotation to the source code itself to exclude the message. This takes the form of an attribute. You can start by right clicking on the message you wish to exclude, go to Copy As, and select “SuppressMessage.” The text that is copied to the clipboard can be pasted almost anywhere in your code. Some people prefer to keep all message suppressions together as much as possible, others keep the suppression as close to the offending code as possible.
The text looks like:
[module: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope="namespace", Target="OvidEast.Xna.Framework")]
The attribute identifies the scope the attribute exists for (the module it is pasted in,) the message to be suppressed, the scope in which the message is to be suppressed (not the same as the scope of the attribute!) and finally a target identifying that scope.
There are other useful properties of the SuppressMessage attribute. The most useful is the “Justification” property. This allows you to add a string to the attribute that explains in human readable terms why the message was suppressed. This is very useful to maintainers to understand why potentially unsafe code was not caught by FxCop.
After adding a Justification string, you’ll find your brand new attribute does not compile. You’ll need to add a reference to the System.Diagnostics.CodeAnalysis namespace to get the attribute. After recompiling again, you’ll find the attribute does not suppress the message. It is also necessary to add a #define (or use the /define compiler switch) for the macro CODE_ANAYSIS.
In the final design, I added CODE_ANLYSIS to my Release and Debug configurations’ /define list. I added a third configuration, cloned from Release, called Ship. Ship does not have CODE_ANLYSIS set. I added this to my references section in each source file:
using System.Diagnostics.CodeAnalysis;
Finally, I added the attribute to the offending source file.
[module: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope="namespace", Target="OvidEast.Xna.Framework", Justification="The OvidEast namespaces mirror the Microsoft layout. These classes belong in the Framework namespace, despite there are only 2 of them.")]
OE
Links of interest:
- MSDN documentation on the SuppressMessageAttribute.
- An FxCop team blog post on why the CODE_ANALYSIS define is necessary.