Technology with opinion

Tuesday, November 25, 2008

Creating Custom StyleCop Rules in C#

Microsoft has released a new free static code analysis tool called StyleCop.  Named after the similar FxCop, this product is aimed to be more focused for cosmetic code consistency which can increase readability and maintainability.  StyleCop has built-in rules, which you can turn off, many of which are:
  • Ordering of members in a class from most visible to least visible
  • Order of Usings in alphabetical order, with System namespaces on top
  • Proper camel casing and pascal casing
  • Proper whitespace
I like about 3/4 of these rules so I think it's definitely worth considering using, even consider integrating into your automated build process using NAnt, CruiseControl or TFS.  That being said many will likely want to extend these rules to create your own.  Doing so is fairly simple but not documented very well at this time.  I created the following rule to make sure that all instance variables (private & protected class level variables) are prefixed with an underscore.  I realize not everybody follows this convention, but I like it because it's more concise than prefixing your instance variables with 'm_' or 'this' which is often needed to prevent name collisions.

First I created a C# Class assembly project and referenced "Microsoft.StyleCop" and "Microsoft.StyleCop.CSharp".  Next I added the following class, which implements my custom rule:

using Microsoft.StyleCop;
using Microsoft.StyleCop.CSharp;

namespace DotNetExtensions.StyleCop.Rules
{
    /// <summary>
    /// This StyleCop Rule makes sure that instance variables are prefixed with an underscore.
    /// </summary>
    [SourceAnalyzer(typeof(CsParser))]
    public class InstanceVariablesUnderscorePrefix : SourceAnalyzer
    {
        
        public override void AnalyzeDocument(CodeDocument document)
        {
            CsDocument csdocument  = (CsDocument) document;
            if (csdocument.RootElement != null && !csdocument.RootElement.Generated)
                csdocument.WalkDocument(new CodeWalkerElementVisitor<object>(this.VisitElement), null, null);
        }

        private bool VisitElement(CsElement element, CsElement parentElement, object context)
        {
            // Flag a violation if the instance variables are not prefixed with an underscore.
            if (!element.Generated && element.ElementType == ElementType.Field && element.ActualAccess != AccessModifierType.Public && 
                element.ActualAccess != AccessModifierType.Internal && element.Declaration.Name.ToCharArray()[0] != '_')
            {
                AddViolation(element, "InstanceVariablesUnderscorePrefix");
            }
            return true;
        }
    }
}

The VisitElement function handles the main logic for this rule.  First it makes sure that the member isn't Generated code, which you have no control over so no sense in applying rules to.  Secondly it's making sure that the member's visibility isn't Public or Internal.  Finally we make sure that the instance variable starts with an underscore prefix..

Next we need to provide metadata so that StyleCop can categorize and describe our rule.  Add an XML file to your project, then change it's Build Action to 'Embedded Resource'

<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Extensions">
  <Description>
    These custom rules provide extensions to the ones provided with StyleCop.
  </Description>
  <Rules>
    <Rule Name="InstanceVariablesUnderscorePrefix" CheckId="EX1001">
      <Context>Instance variables should be prefixed by underscore.</Context>
      <Description>Instance variables are easier to distinguish when prefixed with an underscore.</Description>
    </Rule>
  </Rules>
</SourceAnalyzer>

At the root level you are naming the main category for the rules in this file.  Next you describe your suite of rules.  Then in the Rules section you can add all the rules (note: you can use RuleGroup element to further categorize your rules).  Finally you name your rule and give it a unique CheckId.  The CheckId is what you can search for your rule by in the StyleCop Project Settings.  Important: for StyleCop to correlate your class to your metadata your class and xml file need to be named exactly the same.

Finally build your project and drop your new assembly's dll into the StyleCop directory (C:\Program Files\Microsoft StyleCop 4.3).  Now double-click your Settings.StyleCop to see your rule in the list.  It should look something like the following:



Now you can open your solutions/projects in Visual Studio and click Tools -> Run StyleCop and you should see warnings for your new rule.

StyleCop is a nice little accent to any C# project.  I'd like to see Microsoft make the following changes:
  • StyleCop should be OSS (open source software) - why not Microsoft, there really can't be any proprietary business technology in an application that is basically is performing string  parsing
  • StyleCop's documentation needs to be improved - Microsoft provides to help documents for StyleCop, a user manual and an SDK manual.  Both of them lack details and some of the examples simply do not even compile.  For instance the CodeWalkerElementVisitor delegate in a boolean, in their samples they do not even return a boolean value which will not allow their samples to compile.  They do not even document the purpose of this boolean.  Through trial and error I think that if you return a false that it will stop walking (parsing) the document for this rule.
  • Custom rules should be able to be categorized within the existing main ones: Naming Rules, Ordering Rules, etc.
  • Easier to create custom rules by using regex within an XML file.  This would eliminate having to create custom assemblies and classes.
  • Command-line interface should be available for testing or scripting purposes.

Monday, November 10, 2008

Visual Studio Complaints and Moanings

Visual Studio 2008 has become unbearably slow for me, so I've decided to take some measures.  My first steps was going to include removing the features of Visual Studio that I do not currently use.  Upon attempting to add/remove for Visual Studio I received the following error: 

a problem has been encountered while loading the setup components

So as I research this issue, which seems very common, it seems to be a common theme that people who have patched VS.Net 2008 are having trouble running it's setup. One solution has you install Visual Studio SP1, which I proceeded to install only for it to freeze in the middle.

Next I decided I would just remove the existing hotfixes and patches I have installed for Visual Studio 2008 and then try to add/remove programs for VS.Net 2008.  This worked, I proceeded to remove VB, C++ and database environment.

Finally I was able to apply SP1 to VS.Net 2008, which forced me to reboot.

For those looking to speed up VS.Net a little bit you can try the tips from the following site which seemed to slightly improve the responsiveness for me: dotnettipoftheday.org 

Next I went back into VS.Net 2008 setup to remove some components and removed the following: Enterprise Tools, Dotfuscator Community Edition, Tools for Redistributing Applications, Team Developer and Tester Tools, Team Database Edition and Microsoft SQL Server 2005 Express Edition (actually this was already unchecked).

I then went into add/remove programs and removed: Microsoft Visual Studio Web Authoring Component and the header files (option below I think).  Beware of this however because when I did this I was no longer able to select "Add or Remove Features" within VS.Net setup, my guess is I'd have to 'repair' it first.

These are some of the reasons that Java's Eclipse IDE is so widely popular (in and out of the Java community) because it gives you more granular control over your environment, it's plugins and updates.  This is also why many people, including myself, prefer to have our unit testing and build tools to run outside of the environment.

Heres to one day having a robust C# & ASP.Net plugin for Eclipse.

Tuesday, November 04, 2008

Alt.Net Programmer's Toolbox

Below is my toolbox for most projects.  Just an FYI you only really need to download and install Spring.Net since it includes bins for the other NHibernate, Castle, log4net and NUnit, though you will probably want to download NUnit so you can run the nunit gui.
  • Castle Project - provides IoC, DI and MVC frameworks
  • log4net - mature logging framework for .Net
  • MyGeneration - code generation similar to CodeSmith except open source and free
  • NAnt - build program
  • NHibernate - most mature ORM framework for .Net
  • NUnit - most widely used .Net unit testing framework
  • Spring.Net - enterprise ready framework supports ORM, logging, AOP, Caching through IoC
  • TortoiseCVS - access CVS repositories via Windows Explorer.  Nice to have if you want to get latest source from any open source project
  • TortoiseSVN - access SVN repositories via Windows Explorer.  Nice to have if you want to get latest source from any open source project