Thursday, December 17, 2009

Overlapping dates

Had an interesting problem a few nights ago which at first seemed like a really easy thing, but turned out to be a right pain in the face.  I figured I’d do a blog on it as it might help someone else later on.

A Simple Problem .. not !!

What I wanted to figure out was if two date ranges overlapped.  the logic of this was a lot harder to get my head around than I first expected.  As I was dealing with a range rather than static dates any of the existing DateTime functions were useless, also working with TimeSpans I find difficult.  The solution was to create a good Test case and keep playing around with the logic.

[Test(Description="Test over lapping dates")]
[TestCase("2009-12-17 13:00:00", "2009-12-17 17:00:00", "2009-12-17 13:00:00", "2009-12-17 13:00:00", true)]
[TestCase("2009-12-17 13:00:00", "2009-12-17 13:30:00", "2009-12-17 14:00:00", "2009-12-17 14:30:00", false)]
public void CompareDatesTest(string firstStartDate, string firstEndDate, string secondStartDate, string secondEndDate, bool expectedOverlap)
{
     DateTime first_start_date = DateTime.Parse(firstStartDate);
     DateTime first_end_date = DateTime.Parse(firstEndDate);
     DateTime second_start_date = DateTime.Parse(secondStartDate);
     DateTime second_end_date = DateTime.Parse(secondEndDate);
     //Compare
     Assert.IsTrue(DatesOverlap(first_start_date, first_end_date, second_start_date, second_end_date) == expectedOverlap, "booking overlap validation did not work");
}

the test case above will run two dates through my logic and return True if the first and second date rages overlap, False if they don’t.

My magic function

To work out the problem I had to convert the dates into Ticks.  This converts the date in the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.  Using that conversion I can easily use the numerical Great-than Boolean functions…. so after much playing around with IF statements I came up with:

private bool DatesOverlap(DateTime firstStart, DateTime firstEnd, DateTime secondStart, DateTime secondEnd)
{
     return (firstEnd.Ticks >= secondStart.Ticks) && (secondEnd.Ticks >= firstStart.Ticks);
}

After doing all this I then did a quick Google to find someone had come up with the same solution.  D’oh!.

Friday, December 11, 2009

Reflecting Classes and content

Yesterday someone asked for a way to print out all the contents of a class including the values that were current assigned.  This initially seemed like an easy thing to do, but turned out to be a little more complicated that expected.

The Easy Way

First thing we need to understand about .NET classes is that they are all inherited from a base type called Object.  This base object has a handy little method called ToString(), which will return you a string representation of that object.  You would have used this dozens of times in your code.

int X = 32;
Console.WriteLine("The value of X is:” + X.ToString());

image

This returns “The value of X is:32” which is fine for simple objects like int, float, DateTime but what about our custom classes?.  If you coded up something like the following:

public class SomeObject
{
    public string Firstname { get; set; }
    public string Surname { get; set; }
}

Now you’re test code would look like this:

SomeObject someObject = new SomeObject();
someObject.Firstname = "Tiberius";
someObject.Surname = "Percinus";
Console.WriteLine("The value of someObjectis: " + someObject.ToString());

image

This returns “The value of someObject is: UnitTests.ReflectionExample.SomeObject” which is not really helpful at all.  The normal way around this is to create an override on the ToString() method which returns a more meaningful result.

    public class SomeObject
    {
        public string Firstname { get; set; }
        public string Surname { get; set; }

        /// <summary>
        /// Local implementation of ToString based on class members
        /// </summary>
        public override String ToString()
        {
            StringBuilder sbuffer = new StringBuilder();
            sbuffer.Append("{");
            sbuffer.AppendFormat("Firstname = {0}, ", this.Firstname);
            sbuffer.AppendFormat("Surname = {0}, ", this.Surname);
            sbuffer.Append(" }");
            return sbuffer.ToString();
        }
    }

With this we create a large string with all of the local values returned in a meaningful way.

image 

This returns: “The value of someObject is: {Firstname = Tiberius, Surname = Percinus,  }”.

The Fancy Way

“OK”, I was told, “But this object has only two data items what happens if I’ve got 180?”.  Which is a very valid question.  The best answer to this is to use a technique called “Reflection” which allows you to crack open a class to access its values.

    using System.Reflection;

    public class SomeObject
    {
        public string Firstname { get; set; }
        public string Surname { get; set; }
         //  ……  assume another 180 properties are here ……  //
        public string LastProperty { get; set; }

        /// <summary>
        /// Local implementation of ToString based on reflection
        /// </summary>
        public override String ToString()
        {
            StringBuilder sbuffer = new StringBuilder();
            sbuffer.Append("{");
            PropertyInfo[] properties = this.GetType().GetProperties();
            foreach (PropertyInfo prop in properties)
            {
                sbuffer.AppendFormat("{0} = {1}, ", prop.Name, prop.GetValue(this, null));
            }
            sbuffer.Append(" }");
            return sbuffer.ToString();
        }
    }

Using the foreach loop and the GetType().GetProperties() methods we get an array of all properties in the class.  Then we just have string builder join them all together.

image

This will now return: “The value of someObject is: {Firstname = Tiberius, Surname = Percinus, … and on for all the properties … , LastProperty = ,  }”.

So why not do this all the time? Well the simple reason is that reflection adds a little more load on the processor, so for the majority of cases it’s best to stick to “the easy way”, unless you have a very, very large set of properties.

Tuesday, December 8, 2009

Conditional Pre-Complication is good for what ails you.

Recently found a comments in the code base that stated "Remove on Live!" in the description.  It was perfectly valid code, but unfortunately but there was no way any developer (other than the person who wrote it in the first place) will remove the code before compiling.  The good news is that there is a solution to this problem and that’s "Conditional Pre-Compilation Symbols".  That all sounds very complicated but its really simple.  It means you can mark a section of code, so that it is placed within a specific assembly.

Simple Conditional Pre-Complication

Here is an example of a function that will appear in all environments and assemblies.

//***********************************
// Test code; remove when running on live.
//***********************************
  if (X==Y || Z==A)

{  
      int AnotherX = Convert.ToInt32(X)|
      _log.DebugFormat("AnoterX has been set to {0}", X);
  }

Pleacing this within a Conditional Pre-Compilation Symbols would look like this:

#if(DEBUG)

   //***********************************
   // Test code; remove when running on live.
   //***********************************
   if (X==Y || Z==A
   {  

      int AnotherX = Convert.ToInt32(X)|
      _log.DebugFormat("AnoterX has been set to {0}", X);
    }

#endif

This means that the code still works fine on you're local PC and Miranda, but now that we're using CC.NET to do a "Release" build, this code will not be included in the assembly.

Doing something more funky

You're not limited to just removing code, you can also directly change the code as shown below:

#if(DEBUG)

      _log.DebugFormat("This is Debug Code");

#else

      _log.DebugFormat("This is Release Code");

#endif

You are also not limited to only using the pre-configured "DEBUG" or "RELEASE" variables, you can also set your own.  To do this, open the property page for your project and select the Build tab.  Here you can see a field called "Conditional compilation symbols".  Here you can enter a value like "Design", but you should also note the Configuration currently selected as this is important. 

image

Now in your code you can do this….

  #if(Design)

      _log.DebugFormat("This is only run when Design is entered in the properties");

  #endif

You can of course add as many build configurations as you wish, e.g. “Debug”, “Test”, “Stage”, “Live” etc. and CC.NET will happy ensure that each is built in turn correctly.