Derik Whittaker

Syndication

News


Code Contracts Primer – Part 5: Utilizing Object Invariants

If you are not familiar with the Code Contracts library which is coming out of Microsoft R&D labs, you need to check this pretty cool little library out.  As of Vs2010/.Net 4.0 this library will be making the jump out of the R&D labs. 

Over the next few blog posts we will be taking a look at the topics below.

In this post we are going to take a look at what I think is one of the coolest features of the Contracts Library.  The concept of Object Invariants.

What is Object Invariant validation?

This part of the library ensures that when the state of an object is changed that the object remains in valid state.  If the state of the object is to become invalid then your contract would fail and this would be an issue.

Imagine you have a class called ReportCard, this class is used by a timekeeping system and is used to store instances of daily report cards (a daily report card holds the time/hours worked for that employee).  We want to setup a rule which says that depending on the employee type they are not allowed to work > 40 hours (the actual number is not important).  We also want to setup the ability to ensure they do not work < 0 hours.

Prior to code contracts you would need to create your state checking method and then place calls to the validator at location where the state changes.  This is both tedious and error prone because as your add more code (hopefully you follow the Open/Close principle and extend the class not keep piling on new code, but that is a different post) you have to remember to add the state checking logic.  With invariants you do not need to do that.  All you need to do is below.

[ContractInvariantMethod]
public void EnsureReportHoursIsInValidRange()
{
    Contract.Invariant( EmployeeID > 0 );

    var totalHours = TotalHours(); // Calcs total hours

    Contract.Invariant(totalHours >= 0);
    Contract.Invariant(totalHours <= 40);
}

Taking a look at this code there are a few things you should know

  1. The [ContractInvariantMethod] is what makes this method the invariant checking method
  2. You MUST use Contract.Invariant to do your assertions
  3. You can only have 1 method in your class which has the [ContractInvariantMethod]  attribute (which just makes sense, but thought I would mention it)
  4. The code weaver will add calls to your invariant logic ANY place the state changes in the object.

Here is the same code above, but this time POST code weaving.

public void AddDailyReport(DailyCards dailyCards)
{
	this.DailyReportCards.Add(dailyCards);
        this.EnsureReportHoursIsInValidRange();
}

[ContractInvariantMethod]
public void EnsureReportHoursIsInValidRange()
{
	if (!this.$evaluatingInvariant$)
        {
            this.$evaluatingInvariant$ = true;
            try
            {
                __ContractsRuntime.Invariant(this.EmployeeID > 0, null, "EmployeeID > 0");
                double num = this.TotalHours();
                __ContractsRuntime.Invariant(num >= 0.0, null, "");
                __ContractsRuntime.Invariant(num <= 40.0, null, "totalHours <= 40");
            }
            finally
            {
                this.$evaluatingInvariant$ = false;
            }
        }
}

The key thing to notice when looking at the reflected code is how the weaver added the call this.EnsureReportHoursIsInValidRange(); in the AddDailyReport() method. 

2 Things to watch out for when utilizing the Object Invariant

  1. Remember to make sure that your state validation logic is light and runs quickly.  Because the validation logic will be called EVERY TIME the state changes this logic could be called often.  If your validation does things like reach out to the DB or any other dependency your experience with this will suffer and your performance will also suffer.
  2. When debugging your invariant logic your ‘debug experience’ will not be the same as normal.  When I first started to use this I was confused by the fact that when i would run the code in real time it all worked.  However when I stepped into the code it did not appear to be working correctly.  I have never figured out the EXACT reason for this, but I am 99% sure it has to do with the way the weaver alters the code.

Till next time,


Posted 07-01-2009 5:03 AM by Derik Whittaker

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)