:::: MENU ::::

Tuesday, March 3, 2009

In your applications there may be times when you want to give the user the ability to override a setting or configuration value.  Often times you want to provide sensible defaults so that every single configuration option does not have to be specified, only those you which to override.  I want to show a very simple way to make your applications a bit smarter when creating classes with overridable default values.

Example 1:

   1: public class DemoObejct

   2: {

   3:     private string DEFAULT_MESSAGE = "Thank you for your order";

   4:    

   5:     private string message = DEFAULT_MESSAGE;

   6:    

   7:     public string Message

   8:     {

   9:         get { return message; }

  10:         set { message = value; }

  11:     }

  12: }

Example 2:

   1: public class DemoObejct

   2: {

   3:     private string DEFAULT_MESSAGE = "Thank you for your order";

   4:    

   5:     private string message;

   6:    

   7:     public string Message

   8:     {

   9:         get { return message ?? DEFAULT_MESSAGE; }

  10:         set { message = value; }

  11:     }

  12: }

So what's the difference?  The difference IS subtle but I consider the following code snippet:

   1: var obj = new DemoObject();

   2: 

   3: Console.WriteLine(obj.Message);

   4: 

   5: obj.Message = null;

   6: 

   7: Console.WriteLine(obj.Message);

Setting the Message property to null in line 5 results in different behavior between the two examples.  I find the second example to be preferable, setting the property to null invokes the default message again.  It's a very simple thing you can do to provide a more robust object

Here are two more examples where I use this strategy often:

Integers and Default Values:

   1: public class DemoObject

   2: {

   3:     private int? attemptThreshold;

   4:     private const int DEFAULT_ATTEMPTTHRESHOLD = 3;        

   5:        

   6:     public int AttemptThreshold

   7:     {

   8:         get { return attemptThreshold.HasValue ? attemptThreshold.Value : DEFAULT_ATTEMPTTHRESHOLD; }

   9:         set { attemptThreshold = value; }

  10:     }

  11: }

Logging Component:

   1: public class DemoObject

   2: {

   3:     private ILogger logger;

   4: 

   5:     public ILogger Logger

   6:     {

   7:         get { return logger ?? NullLogger.Instance; }

   8:         set { logger = value; }

   9:     }

  10: }

The above logging example is where this type of strategy really shines.  It prevents NullReferenceExceptions in your code if by chance your logger gets a null value at some point, again providing for a more robust object and application.