Rhino Generators

time to read 26 min | 5062 words

Like I said, I got envious from the Eleutian guys, and I decided to try to implement a very simple task with code preprocessing. After a small false start (choose the wrong code parser), I was able to come up with a preprocessor that could take this:

[PerformanceCounterCategory("TestFoo")]

public abstract class Performance

{

       [PerformanceCounter(PerformanceCounterType.NumberOfItems64)]

       public abstract PerformanceCounter TotalItems { get; }

}

And transform it to something like this:

public class PerformanceDerived : Performance {

   

    private HandleSetup _setup = new HandleSetup();

   

    private System.Diagnostics.PerformanceCounter _TotalItems =
                  
new System.Diagnostics.PerformanceCounter("TestFoo", "TotalItems");

   

    public virtual HandleSetup Setup {

        get {

            return this._setup;

        }

    }

   

    public override System.Diagnostics.PerformanceCounter TotalItems {

        get {

            return this._TotalItems;

        }

    }

   

    public class HandleSetup {

       

        public virtual void Run() {

            if (System.Diagnostics.PerformanceCounterCategory.Exists("TestFoo")) {

                System.Diagnostics.PerformanceCounterCategory.Delete("TestFoo");

            }

            System.Diagnostics.CounterCreationDataCollection counters =
                      
new System.Diagnostics.CounterCreationDataCollection();

            System.Diagnostics.CounterCreationData TotalItems_Counter =
                     
new System.Diagnostics.CounterCreationData();

            TotalItems_Counter.CounterName = "TotalItems";

            counters.Add(TotalItems_Counter);

            System.Diagnostics.PerformanceCounterCategory.Create("TestFoo", "",

                      System.Diagnostics.PerformanceCounterCategoryType.SingleInstance, counters);

        }

    }

}

Which means that I can the do this:

[PerformanceCounterCategory("TestFoo")]

public abstract class Performance

{

       static PerformanceDerived instance = new PerformanceDerived();

 

       public static PerformanceDerived Instance

       {

              get { return instance; }

       }

 

       [PerformanceCounter(PerformanceCounterType.NumberOfItems64)]

       public abstract PerformanceCounter TotalItems { get; }

}

And now I can get:

Performance.Instance.Setup.Run();//init the counters
Performance.Instance.TotalItems.Increment();//use the counters

The main advantage here is that I can sometimes reach to a high number of counters, and it is annoying to try to manage them independently.

At the moment I am having issues trying to decide how I should expose this, though. There are two options:

  • MsBuild Task - Simple & easy, won't run each time that I run the file, will run as part of the build.
  • VS Custom Tool - A bit hard to developer, much harder to deploy, will not run as part of the buiild but will run whenever I change the file.