Wednesday, October 22, 2008

A type-safe pattern to implement ICloneable and similar interfaces

The ICloneable interface contains a single method Clone() that returns a clone of the object.

However the return value is defined as type ‘System.Object’, which means that the user still has to cast this to the actual type:

   1: Test t = new Test();
   2: Test t2 = t.Clone() as Test;    // cast needed

This is cumbersome and error-prone because the cast may fail at runtime.

Use the following pattern to provide a type-safe implementation of this interface:

   1: class Test : ICloneable
   2: {
   3:     int m_Amount;  // just some example data...
   4:     Font m_Font;
   5:     string m_Name;
   6:  
   7:     #region ICloneable Members
   8:  
   9:     // Provide a type-safe implementation
  10:     public Test Clone()
  11:     {
  12:         Test clone = new Test();
  13:         clone.m_Amount = m_Amount;
  14:         clone.m_Font = m_Font.Clone() as Font;
  15:         clone.m_Name = m_Name;
  16:         return clone;
  17:     }
  18:  
  19:     // Provide an "Explicit Interface Method Implementation"
  20:     object ICloneable.Clone()
  21:     {
  22:         return Clone();
  23:     }
  24:  
  25:     #endregion
  26: }

This example implements a type-safe Clone() method, so the user does not have to cast the result. But we still have to implement the interface-method that returns a System.Object. This is done through explicit interface method implementation.

This pattern is easier for the user of the class, and it has the benefit that the compiler will now guarantee that the returned object is always of the correct type.

Wednesday, October 15, 2008

Beware of the stopwatch

In a comment on my last post, craniac argued that the StopWatch-class should be used for measuring time intervals.

Sadly, measuring a time interval is not as easy as it sounds. There are several mechanisms, I will explain 3 of them and point out their strengths and weaknesses.

1. DateTime.UtcNow

   1: DateTime begin = DateTime.UtcNow;
   2:  
   3: ...
   4:  
   5: DateTime end = DateTime.UtcNow;
   6: Console.WriteLine("Measured time: " + (end-begin).TotalMilliseconds + " ms.");

This is the fastest mechanism because under the hood it only reads a counter from memory (the code above takes only 76 nanoseconds to execute on my machine). However the resolution is not so great: only 10 milliseconds on recent version of Windows. If you want to measure a piece of code that takes shorter to execute, you will have to execute it e.g. 1000 times and measure how long this takes, then divide the result by 1000.

Another disadvantage is that this is not reliable if the system-time changes. This should be a very rare situation, but could for instance happen through synchronization with a time server.

2. Stopwatch

   1: Stopwatch watch = new Stopwatch();
   2: watch.Start();
   3:  
   4: ...
   5:  
   6: watch.Stop();
   7: Console.WriteLine("Measured time: " + watch.Elapsed.TotalMilliseconds + " ms.");

This mechanism is a bit slower than the previous one (10 times slower on my machine) so for short intervals this may have an impact on the result. However there are some serious issues:

  • This can be unreliable on a PC with multiple processors. Due to a bug in the BIOS, Start() and Stop() must be executed on the same processor to get a correct result.
  • This is unreliable on processors that do not have a constant clock speed (most processors can reduce the clock speed to conserve energy). This is explained in detail here.

I suspect that you can get a reliable result if you run it on a single-processor machine and disable any power-saving options in the BIOS. I haven’t tested this though.

On the upside, it has the hightest possible resolution (which depends on the hardware it runs on).

3. Process.TotalProcessorTime

   1: TimeSpan begin = Process.GetCurrentProcess().TotalProcessorTime;
   2:  
   3: ...
   4:  
   5: TimeSpan end = Process.GetCurrentProcess().TotalProcessorTime;
   6: Console.WriteLine("Measured time: " + (end - begin).TotalMilliseconds + " ms.");

This mechanism is different from the previous ones because it does not measure how much time has passed, but it measures how long your process has kept the CPU busy. This is great for performance measurements:

  • The timings are not distorted by other processes that consume a lot of CPU.
  • You can measure the impact that your code has on the overall performance of the system. On laptops, this also gives an indication towards the battery-power that is consumed by your process. This can be important for applications that run for a long time (such as services and other background tasks).

To interpret the measured time correctly, you should realize that time that is spent while your code is waiting (e.g. in a Sleep) will not be counted. On the other hand, if your process is keeping multiple processors busy, the time of each processor will be added (if a dual-core processor is kept 100% busy, the ‘TotalProcessorTime’ will increment with 2 each second!).

Note that this mechanism has the worst performance: the code above takes 19264 nanoseconds on my PC. This is 250 times slower than using DateTime.UtcNow!

So there is not one-size-fits-all solution to measure a time interval. Personally, if I want to measure how long a piece of code takes to execute, I run it in a loop (e.g. one million times) and measure it using DateTime.UtcNow.

Wednesday, October 08, 2008

Sometimes it is better to use DateTime.UtcNow instead of DateTime.Now

When you want to measure how long a certain action takes, you should use DateTime.UtcNow instead of DateTime.Now:

   1: DateTime begin = DateTime.UtcNow;
   2:  
   3: ...
   4:  
   5: DateTime end = DateTime.UtcNow;
   6: MessageBox.Show("Time taken: " + (end-begin).TotalMilliseconds);

Reasons:

  • DateTime.UtcNow is more efficient than DateTime.Now (on my PC: 21 nanoseconds versus 575 nanoseconds).
  • More importantly: DateTime.Now will get you into trouble if Daylight Saving Time is enabled. For instance, it is possible that begin contains 02:59:00 and end contains 02:01:00 (while only two minutes have elapsed).

Of course, both mechanisms are incorrect if the user changes his clock (manually or through synchronziation with a time server).

Wednesday, October 01, 2008

Avoid invoking a virtual method in a constructor

You should be very careful when invoking a virtual method in the constructor of a class that is not sealed.

Reason: when the virtual method is overriden in a derived class, this method will be invoked even before the constructor of the derived class has been invoked! This probably was not anticipated by the developer of the derived class!

Take for instance this example:

   1: abstract class Base
   2: {
   3:     public Base() // This constructor calls a virtual method
   4:     {
   5:         Initialize();
   6:     }
   7:  
   8:     protected abstract void Initialize();
   9: }
  10:  
  11: class Derived : Base
  12: {
  13:     FileStream m_File;
  14:  
  15:     public Derived()
  16:     {
  17:         m_File = new FileStream(@"c:\temp\test.txt", FileMode.Open);
  18:     }
  19:  
  20:     protected override void Initialize()
  21:     {
  22:         MessageBox.Show(m_File.Length.ToString());    // NullReferenceException! m_File has not been constructed yet!
  23:     }
  24: }

When an instance of Derived is created, first the constructor of the base class is called. This will result in Derived.Initialize() being called before the constructor of Derived has executed!

Because this is very contra-intuitive, it is best not to invoke virtual methods from a constructor altogether. Except when the class is sealed of course, because then there can be no derived class.

Wednesday, September 24, 2008

Prevent indentation by combining using-statements

C# code tends to be heavily indented:

  • All code is indented at least three levels deep (namespace, class, method).
  • The usage of constructs such as using and try-finally adds further indentation.

Especially in GDI+ drawing code, the usage of using-statements can make the code much more difficult to read:

   1: protected override void OnPaint(PaintEventArgs e)
   2: {
   3:     base.OnPaint(e);
   4:  
   5:     using (Pen thickBlack = new Pen(Color.Black, 5f))
   6:     {
   7:         using (Pen thickRed = new Pen(Color.Red, 5f))
   8:         {
   9:             using (LinearGradientBrush backGround = new LinearGradientBrush(...)
  10:             {
  11:                 // start painting here...
  12:             }
  13:         }
  14:     }
  15: }

This can be simplified by combining the using-statements like this:

   1: protected override void OnPaint(PaintEventArgs e)
   2: {
   3:     base.OnPaint(e);
   4:  
   5:     using (Pen thickBlack = new Pen(Color.Black, 5f))
   6:     using (Pen thickRed = new Pen(Color.Red, 5f))
   7:     using (LinearGradientBrush backGround = new LinearGradientBrush(...)
   8:     {
   9:         // start painting here...
  10:     }
  11: }

As you can see this reduces indentation, making the code easier to read and understand.

Wednesday, September 17, 2008

Prevent unnecessary indentation

Code that is heavily indented is difficult to read (especially if the method does not fit on a single screen anymore).

Instead of this code …

   1: void Test(string input)
   2: {
   3:   if (input != null)
   4:   {
   5:     if (input.Length > 0)
   6:     {
   7:
   8:     }
   9:   }
  10: }

… write this code:

   1: void Test(string input)
   2: {
   3:   if (input == null) return;
   4:   if (input.Length == 0) return;
   5:  
   6:
   7: }

Friday, September 05, 2008

How to use consistent version numbering across multiple projects

If you have many C# projects, you may want all your assemblies to have the same version numbers. Remember that the version numbers are defined in the ‘AssemblyInfo.cs’ file in each project.

There are several mechanisms to achieve this:

  • Programmatically change all the ‘AssemblyInfo.cs’-files to update the version number.
    You could write a tool that updates the version number of all your projects. This tool could then be integrated in your build process. This is cumbersome and often not so simple if your projects are checked in a source control system.
  • Define the version-numbers in a single file that is used by all your projects. This technique is explained in this article.
  • Define the version-numbers in a separate assembly that is referenced by all projects.

In this post I will elaborate on the third mechanism (because I’ve never seen this explained anywhere else).

Create a new C# project (called Metadata.csproj) that contains all the metadata that is shared across your projects. This project is very simple and contains only 1 class:

   1: namespace KristofVerbiest
   2: {
   3:     public static class ProjectMetadata
   4:     {
   5:         public const string FileVersion = "1.5.0.1";
   6:         public const string CompanyName = "Kristof Verbiest";
   7:         public const string Copyright = "Copyright © Kristof Verbiest 2008";
   8:     }
   9: }

Now you can reference this assembly from all your other C# projects, and you can use the data from the ‘AssemblyInfo.cs’ files like this:

   1: [assembly: AssemblyFileVersion(ProjectMetadata.FileVersion)]
   2: [assembly: AssemblyCompany(ProjectMetadata.CompanyName)]
   3: [assembly: AssemblyCopyright(ProjectMetadata.CopyRight)]

Note that the ‘Metadata.dll’ assembly is used by the compiler to fill in the correct metadata. However this assembly is not needed at runtime! So you don’t need to deploy this assembly to your users, it is only needed by the compiler.

Wednesday, September 03, 2008

Assume that someone who is less experienced than you needs to understand your code

Transparency is an important aspect in a project where many developers are working on the same software.

Some developers like to show of how smart they are using complex constructs that are difficult to understand. This is unnecessary and not fair towards their colleagues.

Some examples:

  • Unnecessary usage of the ?: operator and the null coalescing operator. These operators are not commonly known and should only be used if they improve the readability of the code.
  • Complex expressions whose output depends on the operator precedence rules.
  • Usage of anonymous methods.
  • Usage of regular expressions. Regular expressions can be very powerful, but they have the nasty habbit that they tend to be easier to write than to read.
    Consider rewriting your logic using simple string actions. If you really need to use regular expressions, you should document them very well.

If you encounter a situation where one of these techniques really makes sense then of course you should use it. But you should also add some documentation why you are doing it (and maybe include a link to a website that explains the technique).

Wednesday, August 27, 2008

Good code is self-documenting

Picking a good name for a class/method is often very difficult. But if the names are chosen carefully the code often needs no further documentation.

For instance compare these two simple examples (they are functionally equivalent):

   1: /// <summary>
   2: /// Summary for Bounds class
   3: /// </summary>
   4: public class Bounds
   5: {
   6:   public int m_A;    // lower bound
   7:   public int m_B;    // upper bound
   8:  
   9:   /// <summary>
  10:   /// Creates a new Class1 instance
  11:   /// </summary>
  12:   /// <param name="a">the lower bound</param>
  13:   /// <param name="b">the upper bound</param>
  14:   public Bounds(int a, int b)
  15:   {
  16:     // m_A should be the smallest value
  17:     m_A = Math.Min(a, b);
  18:     // m_B should be the biggest value
  19:     m_B = Math.Max(a, b);
  20:   }
  21:
  22: }
   1: public class Bounds
   2: {
   3:   public int m_LowerBound;
   4:   public int m_UpperBound;
   5:  
   6:   /// <remarks>It is OK to provide a & b in the wrong order.</remarks>
   7:   public Bounds(int a, int b)
   8:   {
   9:     // The rest of this class assumes that m_Lowerbound <= m_Upperbound,
  10:     // so we fix it here
  11:     m_LowerBound = Math.Min(lowerBound, upperBound);
  12:     m_UpperBound = Math.Max(lowerBound, upperBound);
  13:   }
  14:
  15: }

Although the second example has less comments, I feel that it is better documented because it is self-describing:

  • The default class-comment that is inserted by Visual Studio is useless. The name of the class is already sufficient documentation.
  • The second example has good names for the fields; further comments are not necessary.
  • The first example has comments about stuff that is very obvious (every developer should already know what a constructor does).
  • The first example explains the sorting of the parameters but every developer can see what is going on. The second example instead explains why the parameters need to be sorted.

If your code is written cleanly then you don’t have to document what it is doing. But you may have to document why it is doing it.