Thursday, May 08, 2008

Implementing Properties: Basic Considerations

Not too long ago I wrote about Property Getters with bad manors (here). I suggested ways for doing better but I would like to share more of how I generally implement properties in C# (also applicable for other .NET languages). I'm not claiming that my style is the only one or the best one. However, it works good for me and it is based on 7 years .NET development experience and over 15 years experience with C++. Where to start? For this post I would like to focus on very simple things. Suppose you have a class Foo that has a field named _bar (note that I prefix all fields with and underscore; not necessarily what MS recommends but I think that it improves the readability of the code). So the code would look as follows:
public class Foo {
   private string _bar;
}
Now we want to add an accessor aka the getter:
public class Foo {
   public string Bar {
      get {
         return _bar;
      }
   private string _bar;
}
This has been the easy part. There is not really a lot that can go wrong.

It starts to become more interesting when you add a modifier aka a setter. In it's most simple form you could write:

public class Foo {
   public string Bar {
      get {
         return _bar;
      }
      set {
         _bar = value;
      }
   private string _bar;
}
Easy you think. But hang on. There is more to it. You may want to decide whether it is acceptable to pass in a null reference or not. Whether you allow for null or not is a decision that should be made based on a number of factors. One way to find out is to look at all the places in your code where the getter is used. What would happen to that code if null would be returned? For example:
Foo foo = new Foo();
...
if( foo.Bar.Length > 25 ) {
   ...
}
...
In that case if null was returned this piece of code would crash. You could fix this issue by checking for nullness:
Foo foo = new Foo();
...
if(   foo.Bar != null
   && foo.Bar.Length > 25 ) {
   ...
}
...
This certainly work but you pay the price of a slightly less readable code. In addition you may have to have this in a lot of places. So in essence you may decide that the property Foo.Bar doesn't allow for null values. The code for class Foo would then look as this:
public class Foo {
   public string Bar {
      get {
         return _bar;
      }
      set {
         if( value != null ) {
            _bar = value;
         }
      }
   private string _bar;
}
This clearly provides the benefit of Foo.Bar never being null since upon initialization _bar will be initialized with string.Empty or "".

But again this comes at a price. The setter simply swallows the attempt to set Foo.Bar to null. This might be desirable. I personally prefer that a class doesn't swallow incorrect things but instead fails fast. In this particular case I would want my code to indicated the error by throwing an exception:

public class Foo {
   public string Bar {
      get {
         return _bar;
      }
      set {
         if( value != null ) {
            _bar = value;
         }
         else {
            throw new ArgumentNullException("value");
         }
      }
   private string _bar;
}
You see that although this is a simple property implementation it can already require quite a few decisions to be made and aspects to be considered.

To close off this particular post, I'd like to also bring performance considerations into the picture. What if the setter needs to validate any new value against a remote system such as a service? Let's look at the possible code:

public class Foo {
   public string Bar {
      get {
         return _bar;
      }
      set {
         if( value != null ) {
            if( _validationService.IsPermitted(value) ) {
               _bar = value;
            }
            else {
               throw new
                  ArgumentOutOfRangeException("value");
            }
         }
         else {
            throw new ArgumentNullException("value");
         }
      }
   private string _bar;
   private ValidationService _validationService = 
                                 new ValidationService(...);
}
Calling IsPermitted() can be quite expensive. So how to avoid this? Here is one possible solution:
public class Foo {
  public string Bar {
    get {
      return _bar;
    }
    set {
      if( _bar != value ) {
        if( value != null ) {
          if( _validationService.IsPermitted(value) ) {
            _bar = value;
          }
          else {
            throw new
                    ArgumentOutOfRangeException("value");
          }
        }
        else {
          throw new ArgumentNullException("value");
        }
      }
    }
  private string _bar;
  private ValidationService _validationService = 
                                 new ValidationService(...);
}
With this implementation the validation service is called only if the value has actually changed. Certainly if the set of permitted values is dynamic this implementation would not make the cut. With this post I want to demonstrate that even property that looks like an easy thing to do already requires a lot of considerations. We even touched performance briefly. It is important that we are aware of all of these aspects when implementing and testing such a property. There are more aspects to this but I think I've made my point. Even with simple things like properties there are already a quite a few aspects to consider.

0 comments:

Post a Comment

All comments, questions and other feedback is much appreciated. Thank you!